• Stars
    star
    804
  • Rank 54,647 (Top 2 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created about 12 years ago
  • Updated about 7 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

db.js is a wrapper for IndexedDB to make it easier to work against

Build Status Selenium Test Status npm version bower version License

Selenium Test Status

db.js

db.js is a wrapper for IndexedDB to make it easier to work against, making it look more like a queryable API.

Usage

Add a reference to db.js in your application before you want to use IndexedDB:

<script src='/dist/db.js'></script>

Alternatively, db.js includes an optional define call, and can be loaded as a module using the AMD loader of your choice.

Opening/Creating a database and connection

Once you have the script included you can then open connections to each different database within your application:

var server;
db.open({
    server: 'my-app',
    version: 1,
    schema: {
        people: {
            key: {keyPath: 'id', autoIncrement: true},
            // Optionally add indexes
            indexes: {
                firstName: {},
                answer: {unique: true}
            }
        }
    }
}).then(function (s) {
    server = s;
});

Note that open() takes an options object with the following properties:

  • version - The current version of the database to open. Should be an integer. You can start with 1. You must increase the version if updating the schema or otherwise the schema property will have no effect.

  • server - The name of this server. Any subsequent attempt to open a server with this name (and with the current version) will reuse the already opened connection (unless it has been closed).

  • schema - Expects an object, or, if a function is supplied, a schema object should be returned). A schema object optionally has store names as keys (these stores will be auto-created if not yet added and modified otherwise). The values of these schema objects should be objects, optionally with the property "key" and/or "indexes". The "key" property, if present, should contain valid createObjectStore parameters (keyPath or autoIncrement). The "indexes" property should contain an object whose keys are the desired index keys and whose values are objects which can include the optional parameters and values available to createIndex (unique, multiEntry, and, for Firefox-only, locale). Note that the keyPath of the index will be set to the supplied index key, or if present, a keyPath property on the provided parameter object. Note also that when a schema is supplied for a new version, any object stores not present on the schema object will be deleted.

A connection is intended to be persisted, and you can perform multiple operations while it's kept open.

In the event a connection has already been opened for modification (whether in the same instance or in another tab/window), a blocking error will occur, for which you can listen by adding a Promise.catch statement and communicate with blocking instances still holding a connection so that they may close the connection. You can then return the resume property (a promise) to recover to continue the original open operation and proceed to the following then condition.

var server;
db.open({
    // ...
}).catch(function (err) {
    if (err.type === 'blocked') {
        oldConnection.close();
        return err.resume;
    }
    // Handle other errors here
    throw err;
}).then(function (s) {
    server = s;
    // One can add a versionchange handler here to self-close
    //   the connection upon future upgrade attempts (likely to
    //   be one made in other tabs) and thereby
    //   avoid such attempts having to face blocking errors.
});

Check out the /tests/specs folder for more examples.

General server/store methods

Note that by default the methods below (not including close, addEventListener, and removeEventListener) can be called either as server.people.xxx( arg1, arg2, ... ) or server.xxx( 'people', arg1, arg2, ... ).

To reduce some memory requirements or avoid a however unlikely potential conflict with server method names, however, one may supply noServerMethods: true as part of options supplied to db.open() and under such conditions, only the second method signature above can be used.

Store modification

Adding items

server.people.add({
    firstName: 'Aaron',
    lastName: 'Powell',
    answer: 42
}).then(function (item) {
    // item stored
});

Multiple items can be added as additional arguments to add. Another way multiple items can be added is when an array is supplied for any of the arguments in which case, its top level contents will be treated as separate items. If you want unambiguous results where the data to be added could itself be an array, be sure to wrap item supplied in your argument within an array.

Note also when add is provided with objects containing a property item (and optionally a key property), the value of item will be treated as the record to be added, while any key will be used as the key. To supply unambiguous items (where you are not sure whether item may exist on the record to be added), you may wish to consistently wrap your items within an object with an item property even if you are not supplying a key.

Updating

server.people.update({
    firstName: 'Aaron',
    lastName: 'Powell',
    answer: 42
}).then(function (item) {
    // item added or updated
});

As with add, update shares the same behaviors as far as flattening of the top level of array arguments and checking of item/key properties, so if you need unambiguous results, please see the discussion above.

Using update will cause a record to be added if it does not yet exist.

put is also available as an alias of update.

Removing

server.people.remove(1).then(function (key) {
    // item removed
});

delete is also available as an alias of remove.

Clearing

This allows removing all items in a table/collection:

server.people.clear()
    .then(function() {
        // all table data is gone.
    });

Fetching

Getting a single object by key

server.people.get(5)
    .then(function (results) {
        // do something with the results
    });

Getting a single object by key range

If more than one match, it will retrieve the first.

With a MongoDB-style range:

server.people.get({gte: 1, lt: 3})
    .then(function (results) {
        // do something with the results
    });

With an IDBKeyRange:

server.people.get(IDBKeyRange.bound(1, 3, false, true))
    .then(function (results) {
        // do something with the results
    });

Querying

Queries require one or more methods to determine the type of querying (all items, filtering, applying ranges, limits, distinct values, or custom mapping--some of which can be combined with some of the others), any methods for cursor direction, and then a subsequent call to execute() (followed by a then or catch).

Querying all objects
server.people.query()
    .all()
    .execute()
    .then(function (results) {
        // do something with the results
    });
Querying using indexes
server.people.query('specialProperty')
    .all()
    .execute()
    .then(function (results) {
        // do something with the results (items which possess `specialProperty`)
    });
Querying with filtering

Note that unlike the other methods after a query, filter can be executed multiple times.

Filter with property and value
server.people.query()
    .filter('firstName', 'Aaron')
    .execute()
    .then(function (results) {
        // do something with the results
    });
Filter with function
server.people.query()
    .filter(function(person) {return person.group === 'hipster';})
    .execute()
    .then(function (results) {
        // do something with the results
    });
Querying for distinct values

Will return only one record:

server.people
    .query('firstName')
    .only('Aaron')
    .distinct()
    .execute()
    .then(function (data) {
        //
    });
Querying with ranges

All ranges supported by IDBKeyRange can be used (only, bound, lowerBound, upperBound).

server.people.query('firstName')
    .only('Aaron')
    .then(function (results) {
        // do something with the results
    });

server.people.query('answer')
    .bound(30, 50)
    .then(function (results) {
        // do something with the results
    });

MongoDB-style ranges (as implemented in idb-range-driven libraries) are also supported:

server.people.query('firstName')
    .range({eq: 'Aaron'})
    .then(function (results) {
        // do something with the results
    });

server.people.query('answer')
    .range({gte: 30, lte: 50})
    .then(function (results) {
        // do something with the results
    });

Note that IndexedDB allows you to use array keys within ranges (and other methods where a key is accepted) as long as you have created your store with an array keyPath (and optionally with an index keyPath).

// The definition:
schema: {
    people: {
        key: {
            keyPath: ['lastName', 'firstName']
        },
        indexes: {
            name: {
                keyPath: ['lastName', 'firstName']
            },
            lastName: {},
            firstName: {}
        }
    }
}

// ...elsewhere...

// The query:
s.test.query('name')
    .only(['Zamir', 'Brett'])
    .execute()
    .then(function (results) {
        // do something with the results
    });
Limiting cursor range

Unlike key ranges which filter by the range of present values, one may define a cursor range to determine whether to skip through a certain number of initial result items and to select how many items (up to the amount available) should be retrieved from that point in the navigation of the cursor.

server.people
    .query('firstName')
    .all()
    .limit(1, 3)
    .execute()
    .then(function (data) {
        // Skips the first item and obtains the next 3 items (or less if there are fewer)
    });

Cursor direction (desc)

The desc method may be used to change cursor direction to descending order:

server.people.query()
    .all()
    .desc()
    .execute()
    .then(function (results) {
        // Array of results will be in descending order
    });

Retrieving special types of values

Keys

Keys may be retrieved with or without an index:

server.people.query('firstName')
    .only('Aaron')
    .keys()
    .execute()
    .then(function (results) {
        // `results` will contain one 'Aaron' value for each
        //    item in the people store with that first name
    });
Mapping

The map method allows you to modify the object being returned without correspondingly modifying the actual object stored:

server.people
    .query('age')
    .lowerBound(30)
    .map(function (value) {
        return {
            fullName: value.firstName + ' ' + value.lastName,
            raw: value
        };
    })
    .execute()
    .then(function (data) {
        // An array of people objects containing `fullName` and `raw` properties
    });
Counting

To count while utilizing an index and/or the query-returned methods, you can use the following:

server.people.query('firstName')
    .only('Aaron')
    .count()
    .execute()
    .then(function (results) {
        // `results` will equal the total count of "Aaron"'s
    });

If you only need a count of items in a store with only a key or range, you can utilize server.count:

// With no arguments (count all items)
server.people.count().then(function (ct) {
    // Do something with "ct"
});

// With a key
server.people.count(myKey).then(function (ct) {
    // Do something with "ct"
});

// With a MongoDB-style range
server.people.count({gte: 1, lt: 3}).then(function (ct) {
    // Do something with "ct"
});

// With an IDBKeyRange range
server.people.count(IDBKeyRange.bound(1, 3, false, true)).then(function (ct) {
    // Do something with "ct"
});

Atomic updates

Any query that returns a range of results can also be set to modify the returned records automatically. This is done by adding .modify() at the end of the query (right before .execute()).

modify only runs updates on objects matched by the query, and still returns the same results to the Promise's then() method (however, the results will have the modifications applied to them).

Examples:

// grab all users modified in the last 10 seconds,
server.users.query('last_mod')
    .lowerBound(new Date().getTime() - 10000)
    .modify({last_mod: new Date.getTime()})
    .execute()
    .then(function(results) {
        // now we have a list of recently modified users
    });

// grab all changed records and atomically set them as unchanged
server.users.query('changed')
    .only(true)
    .modify({changed: false})
    .execute()
    .then(...)

// use a function to update the results. the function is passed the original
// (unmodified) record, which allows us to update the data based on the record
// itself.
server.profiles.query('name')
    .lowerBound('marcy')
    .modify({views: function(profile) { return profile.views + 1; }})
    .execute()
    .then(...)

modify changes will be seen by any map functions.

modify can be used after: all, filter, ranges (range, only, bound, upperBound, and lowerBound), desc, distinct, and map.

Other server methods

Closing connection

server.close();

Retrieving the indexedDB.open result object in use

var db = server.getIndexedDB();
var storeNames = db.objectStoreNames;

Server event handlers

All of the following are optional.

server.addEventListener('abort', function (e) {
    // Handle abort event
});
server.addEventListener('error', function (err) {
    // Handle any errors (check err.name)
});
server.addEventListener('versionchange', function (e) {
    // Be notified of version changes (can use e.oldVersion and e.newVersion)
});

All of the following shorter equivalent forms (which also work internally via addEventListener) are optional and can be chained as desired.

server.abort(function (e) {
    // Handle abort event
}).error(function (err) {
    // Handle any errors (check err.name)
}).versionchange(function (e) {
    // Be notified of version changes (can use e.oldVersion and e.newVersion)
});

See the IndexedDB spec for the possible exceptions.

Deleting a database

db.delete(dbName).then(function (ev) {
    // Should have been a successful database deletion
}, function (err) {
    // Error during database deletion
});

Note that, in line with the behavior of the deleteDatabase method of IndexedDB, delete will not actually produce an error if one attempts to delete a database which doesn't exist or even if a non-string is supplied.

However, as with the open operation, a delete operation will produce an error so long as there are already opened blocking connections (i.e., those allowing for database modification) which are open elsewhere in the browser. You can nevertheless recover as follows:

db.delete(dbName).catch(function (err) {
    if (err.type === 'blocked') {
        oldConnection.close();
        return err.resume;
    }
    // Handle other errors here
    throw err;
}).then(function (ev) {
    // Should have been a successful database deletion
});

See the documentation on open for more on such recovery from blocking connections.

Comparing two keys

Returns 1 if the first key is greater than the second, -1 if the first is less than the second, and 0 if the first is equal to the second.

db.cmp(key1, key2).then(function (ret) {
    // Use `ret`
});

Promise notes

db.js used the ES6 Promise spec to handle asynchronous operations.

All operations that are asynchronous will return an instance of the ES6 Promise object that exposes a then method which will take up to two callbacks, onFulfilled and onRejected. Please refer to the ES6 Promise spec for more information.

As of version 0.7.0 db.js's Promise API is designed to work with ES6 Promises, please polyfill it if you would like to use another promise library.

Contributor notes

  • npm install to install all the dependencies

In browser:

  • npm run grunt test:local to run the mocha server
  • Open (http://localhost:9999/tests)[] to run the mocha tests

In Node.js:

  • npm test

or to avoid Saucelabs if set up:

  • npm run grunt phantom

or to also avoid PhantomJS:

  • npm run grunt dev

License

The MIT License

Copyright (c) 2012-2015 Aaron Powell, Brett Zamir

More Repositories

1

httpstatus

Easily generate different HTTP responses for testing
C#
608
star
2

html2jade-website

A website for converting (and testing) HTML 2 Jade
JavaScript
189
star
3

vscode-profile-switcher

A VS Code extension for switching settings easily
TypeScript
178
star
4

Postman

The Postman will help you deliver messages around your JavaScript application
JavaScript
140
star
5

ps-nvm

PowerShell module for managing multiple Node.js versions
PowerShell
126
star
6

sublime-jquery-snippets

Code snippets for developing with jQuery
108
star
7

linq-in-javascript

An implementation of LINQ in JavaScript use ES6 iterators for proper lazy evaluation
JavaScript
81
star
8

FSharp.CosmosDb

An F# wrapper around Cosmos DB's .NET SDK to make it more friendly for F# developers
F#
74
star
9

azure-remix-stack

A remix stack template for running a remix app on Azure
Bicep
73
star
10

webpack-golang-wasm-async-loader

A webpack loader for generating Golang WebAssembly bundles using an async interaction model for calling the Golang code from JavaScript
JavaScript
72
star
11

Chauffeur

Welcome to Chauffeur, deliverying changes to your Umbraco environment in style.
JavaScript
68
star
12

docker-from-scratch

Exercises can be found: https://github.com/aaronpowell/docker-from-scratch/wiki
Dockerfile
64
star
13

DisappointinglyAttributed

Express just how dissapointed you are with others code through attributes!
F#
61
star
14

system-init

Shell
57
star
15

dotnet-delice

📑 A CLI to help you get insight into your projects' licenses
F#
54
star
16

graphql-typescript-workshop

This is a series of exercised to learn how to implement a GraphQL server with TypeScript and do end-to-end type-safety
Shell
52
star
17

tmux-weather

Display weather information in tmux status bar
Shell
35
star
18

tbd

tbd, a JavaScript test data generator
JavaScript
34
star
19

azure-functions-nodejs-openapi

TypeScript
22
star
20

mathy.js

Mathy.js is a simple formula parsing library
JavaScript
20
star
21

react-static-web-apps-auth

A package to make it easier to work with authenticated React apps and Azure Static Web Apps
TypeScript
18
star
22

glimpse-knockout

A Glimpse plugin for inspecting KnockoutJS
JavaScript
17
star
23

ConsoleGPT

ConsoleGPT
C#
16
star
24

graphql-code-generator-sample

This is a sample application using GraphQL Code Generator to convert the GraphQL schema to TypeScript types.
TypeScript
16
star
25

delivR

A port of Delivery.js to SignalR
JavaScript
16
star
26

swa-feliz-template

A GitHub repo template for creating Fable + Feliz apps for Azure Static Web Apps
Shell
13
star
27

aswa-react-template

A template for creating Azure Static Web Apps using React
TypeScript
13
star
28

graphql-azure-subscriptions

TypeScript
12
star
29

go-wasm-experiments

Experimenting with go + wasm
TypeScript
11
star
30

sunshine

Sunshine is an application I use to monitor my solar panels, and is a demo of building an IoT project using Azure.
F#
11
star
31

swa-elmish-template

A GitHub repo template for Elmish apps for Azure Static Web Apps
Shell
11
star
32

BrowserStack-.NET

A .NET API from the BrowserStack automated testing API
C#
11
star
33

aswa-trivia-app

A simple trivia app in React with a GraphQL backend, deployed to Azure Static Web Apps
TypeScript
11
star
34

git-indexeddb

git-indexeddb is an implementation of a js-git db on top of IndexedDB
JavaScript
11
star
35

oz-dev-events

An experiment with WebAssembly + Go on how to build it into a normal web dev pipeline
TypeScript
10
star
36

hybrid-next-on-swa

JavaScript
10
star
37

aaronpowell.github.io

My website
CSS
10
star
38

azure-static-web-apps-api-auth

A package to make it easier to work with Azure Static Web Apps auth in the API backend
HTML
10
star
39

blazor-devto-offline

A demo of how to create DEV.to's offline page using Blazor
HTML
10
star
40

dotnet-graphql-cosmosdb

An example of how to create a .NET GraphQL server on Azure Functions that talks to CosmosDB
C#
9
star
41

Reducks.FSharp

An imagining of Redux as Reducks, written in F#
F#
9
star
42

react-foldable

A set of components to help you work with foldable screens
TypeScript
9
star
43

swa-fable-template

A template for creating F# Azure Static Web Apps, using Fable for the UI
Shell
8
star
44

seq-docker

A docker image for running seq
PowerShell
8
star
45

Owin.HelloWorld

A Hello World implementation on OWIN
C#
8
star
46

vscode-espruino

A Visual Studio Code plugin for working with Espruino
TypeScript
8
star
47

Owin.AuthenticatedTests

JavaScript
7
star
48

Sublime-KnockoutJS-Snippets

Code snippets for KnockoutJS
7
star
49

keystone-6-azure-example

A sample application for running Keystone 6 on Azure
TypeScript
7
star
50

fsharp-swa-trivia-app

F#
6
star
51

typescript-pubsub

Run "tsc -sourcemap pubsub.ts" for a Source Map demo
6
star
52

apollo-graphql-appinsights

An example of how to integrate AppInsights into Apollo GraphQL
TypeScript
6
star
53

trivia-api

JavaScript
6
star
54

GenerateAndChill

A demo app of how to use Azure OpenAI Service to generate verify prompts and generate images.
Bicep
6
star
55

azure-functions-graphql

An example of how to create a GraphQL server on Azure Functions
TypeScript
5
star
56

reply

A simple React-based chat application
JavaScript
5
star
57

pinboard-bridge

JavaScript
5
star
58

react-app-insights

JavaScript
5
star
59

KnockoutJS-Pre-parser

A pre-parser for KnockoutJS to use more convention-based discovery for the data binding
JavaScript
5
star
60

appservice-graphql-dotnet

A sample of an ASP.NET GraphQL server
C#
5
star
61

Surrealism

An implementation of Surreal.js - https://github.com/coldhead/surreal.js, a Surreal Number generator written in .NET. Includes basic arithmatic operations
C#
5
star
62

aci-from-scratch

A series of exercises to get you to learn Azure Container Instances
5
star
63

WhatKey

A simple little website for testing JavaScript keyboard events
JavaScript
4
star
64

redux-ko

An example of how to create a custom binding for redux, using knockoutjs
HTML
4
star
65

aspnet-vnext-samples

A series of samples for ASP.NET vNext
C#
4
star
66

dab-library-blazor-sample

HTML
4
star
67

talks

Various talks I've given
CSS
3
star
68

cosmosdb-conf-fsharp

F#
3
star
69

flight-mode-blog

Code for the blog post series http://www.aaron-powell/flight-mode/introduction
JavaScript
3
star
70

Bob

Bob wasn't a great product for Microsoft but maybe Bob can add what's missing for Windows 8
C#
3
star
71

Kendo-UI-Bootstrapper

A library to make object-based Kendo UI development easier
JavaScript
3
star
72

uRested

A convenience wrapper around the Umbraco RestApi to remove the boilerplate you would have to write
C#
3
star
73

dab-blazor-trivia-demo

A demo application using Blazor and SWA Database Connections
CSS
3
star
74

typed-typescript-functions-demo

A demo on how to type the various components of TypeScript Azure Functions
TypeScript
3
star
75

blog-card-generator

Generate an open-graph friendly image from a blog post
F#
3
star
76

indexeddb-filesystem

A sample of how to implement a file system in indexedDB
JavaScript
3
star
77

swa-custom-auth-auth0

A sample of how to setup SWA custom OIDC providers using Auth0
TypeScript
3
star
78

durable-cinema

A sample SPA that uses Azure Functions for the backend
TypeScript
2
star
79

glue

Glue will stick your objects into your HTML
JavaScript
2
star
80

react-workshop-redux

JavaScript
2
star
81

uduf-2019-testing-umbraco

Samples from my testing Umbraco talk from uduf 2019
JavaScript
2
star
82

react-workshop-hoc

JavaScript
2
star
83

Medallion.js

An API for WinJS badges that's like designed for JavaScript development
JavaScript
2
star
84

luke.net

C#
2
star
85

JavaScript-Quiz

Source code and blog for JavaScript Quiz
CoffeeScript
2
star
86

durable-functions-workflow-demo

A simple demo of how Durable Functions can be used for a workflow
F#
2
star
87

redux-rx-demo

A demo of using redux as an observable stream and combining it with rxjs
JavaScript
2
star
88

doinnothin

A site for tracking when you're doing nothing
JavaScript
2
star
89

Chauffeur.uSync

A plugin for Chauffeur for integrating with uSync
CSS
2
star
90

QLDITRelief

A small website to getting IT relief for the Queensland flood victims
Ruby
2
star
91

react-workshop-2018-impl

JavaScript
2
star
92

end-to-end-graphql-workshop

TypeScript
2
star
93

1password-cli-docker

Dockerfile for creating an image containing the 1password cli tool
PowerShell
2
star
94

nextjs-graphql-trivia-demo

Shell
2
star
95

Coffeepud

Notepud with coffee
JavaScript
2
star
96

token-store-demo

A sample of how to use token store from JavaScript and .NET
HTML
2
star
97

wdyk

What Do You Know - Hosted ALL The Things
JavaScript
2
star
98

gatsby-static-web-app

CSS
1
star
99

javascript-compression-tests

JavaScript compression tests
JavaScript
1
star
100

react-workshop-hello-react

HTML
1
star