It will automatically handle transactions and reuse them as many times as possible within the same event loop. You can therefore Ndex.get
in a loop and Ndex will still only create a single transaction for maximum performance.
Ndex methods return a Promise, which means you can chain them or call them concurrently with Promise.all
.
// Result is accessible via .then
Ndex.users.get(1).then(function(data) {
console.log(data) // => { id: 1 }
})
// All you can chain™
Ndex.open('test', migrations)
.then(function() {
return Promise.all([
Ndex.users.add({ id: 1, name: 'e' })
Ndex.users.add({ id: 2, name: 'r' })
])
})
.then(function() {
return Ndex.users.get(1)
})
.then(function() {
console.log('done')
})
CoffeeScript sweetness
# Haters gonna hate
Ndex.open('test', migrations)
.then -> Promise.all([
Ndex.users.add(id: 1, name: 'e')
Ndex.users.add(id: 2, name: 'r')
])
.then -> Ndex.users.get(1)
.then -> console.log('done')
Before using Ndex, you must always open a connection with the database. You must provide a name and a migrations object. You don’t have to provide a database version, Ndex will take care of that for you. See the migrations section.
Ndex.connect('test', migrations).then(function(connection) {
connection.users.get(1).then(function(userData) {
console.log(userData)
})
})
Connection#get
returns a single item (unless an array of keys is passed) even if multiple items match the search for it doesn’t use a cursor. If you want all results (i.e. Connection.users.index('job').get('developer')
) use Connection#where
.
connection.users.get(1)
connection.users.get([1, 4])
connection.users.getAll()
Connection#add
overwrites the entry with the data passed.
// Don’t provide a key for objectStores with a keyPath
connection.users.add({ id: 1, name: 'e', job: 'developer' })
connection.users.add([
{ id: 1, name: 'e', job: 'developer' },
{ id: 2, name: 'r', job: 'developer' },
])
// Provide a key for objectStores without keyPath
connection.organizations.add('missive', { name: 'missive', est: 2014 })
connection.organizations.add(
['missive', 'heliom'],
[
{ name: 'missive', est: 2014 },
{ name: 'heliom', est: 2012 },
]
)
Connection#update
only updates passed data without overwriting the entry. It will also insert the entry when non-existent.
connection.users.get(1) // { id: 1, name: 'e' }
// Waiting for the update success is required for the get to be accurate
connection.users.update(1, { name: 'r' }).then(function() {
connection.users.get(1) // { id: 1, name: 'r' }
})
Connection#increment
initializes attribute to zero if null and adds the value passed (default is 1). Only makes sense for number-based attributes.
// For objectStores without keyPath
connection.stats.increment('visits') // Increments visits entry by 1
connection.stats.increment('visits', 4) // Increments visits entry by 4
// For objectStores with a keyPath
connection.stats.increment(1, { count: 1 }) // Increments id 1’s count attribute by 1
connection.stats.increment(1, { visits: { count: 4 }}) // Increments id 1’s visits.count by 4
Ndex#decrement
is an alias for Ndex#increment
where the value passed is changed to a negative.
connection.stats.decrement('visits') // Increments visits entry by -1
connection.stats.decrement('visits', 4) // Increments visits entry by -4
connection.users.delete(1)
connection.users.delete([1, 4])
connection#deleteWhere
is an alias for Ndex#where:remove
, see Ndex#where
.
connection.users.deleteWhere({ gteq: 3 })
connection.users.index('job').deleteWhere({ eq: 'developer' })
Clear the given object store. Note that if the object store has an autoIncrement: true
key, the key won’t be reseted.
connection.users.clear()
connection.clearAll()
Indexes can be used with get
, getAll
and where
.
connection.users.index('job').get('developer')
Connection#where
uses a cursor to iterate on a given range. Use the keyPath predicates to narrow down your range and the keys predicates to filter items in your range. For maximum performance, you really want to be as precise as possible with the range.
// keyPath predicates
// These will be applied to your objectStore’s key
connection.users.where({ lt: 3 })
connection.users.where({ lteq: 3 })
connection.users.where({ gt: 3 })
connection.users.where({ gteq: 3 })
connection.users.where({ eq: 3 })
// :eq also supports arrays. It will create a range between min (1) and max (3) (both inclusive) and filter out any results that aren’t 1 or 3 (2)
// Depending on the range it creates (i.e. `eq: [1, 1000]`), `Ndex.get([1, 1000])` will definitely be much more performant
connection.users.where({ eq: [1, 3] })
// When using an index, the predicate is applied to the index’s key
connection.users.index('job').where({ eq: 'developer' })
// Any keys predicates
// These can be used on any keys, even the non-indexed ones
connection.users.where({ only: { job: ['developer'] } })
connection.users.where({ except: { job: ['developer'] } })
connection.users.where({ uniq: 'job' })
// Pagination
connection.users.where({ limit: 3 })
connection.users.where({ offset: 2 })
connection.users.where({ order: 'desc' })
// By adding the :remove key, Ndex will delete found items from indexedDB
connection.users.where({ gteq: 3, remove: true }) // Is equivalent to `connection.users.deleteWhere({ gteq: 3 })`
With Ndex, you don’t have handle the database version. It will always increase on each reload. Fear not! Ndex is aware of its migrations and will never run the same migration twice. We haven’t experienced any performance issue with that checkup (that is done with the existing transaction when opening the database).
- createObjectStore#Parameters
- deleteObjectStore#Parameters
- createIndex#Parameters
- deleteIndex#Parameters
migrations = {
'201412041358_CreateUsersObjectStore': {
type: 'createObjectStore',
args: ['users', { keyPath: 'id', autoIncrement: true }],
},
'201412041527_CreateOrganizationsObjectStore': [
{ type: 'createObjectStore', args: ['organizations'] },
{ type: 'createIndex', args: ['organizations', 'est', 'est'] },
],
'201412041527_AddJobIndexToUsers': {
type: 'createIndex',
args: ['users', 'job', 'job'],
},
}
Ndex has a logging system that will group requests by transaction. Gives you a pretty accurate idea of what Ndex does for you and where you can refactor your requests. You can implement your own handler of use the built-in console one.
connection.handleLogging(console)
connection.users.add({ id: 1, name: 'e', job: 'developer' })
connection.users.add({ id: 2, name: 'r', job: 'developer' })
connection.users.add({ id: 3, name: 'p', job: 'developer' })
connection.users.add({ id: 4, name: 't', job: 'designer' })
setTimeout(function() {
connection.users.get(1)
connection.users.get(3)
}, 100)
Without the timeout, Ndex will reuse the same transaction
connection.handleLogging(console)
connection.users.add({ id: 1, name: 'e', job: 'developer' })
connection.users.add({ id: 2, name: 'r', job: 'developer' })
connection.users.add({ id: 3, name: 'p', job: 'developer' })
connection.users.add({ id: 4, name: 't', job: 'designer' })
connection.users.get(1)
connection.users.get(3)
$ gulp dist
$ gulp
$ open http://localhost:8080/spec