Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
7046 lines (5326 sloc) 249 KB
<pre class=metadata>
Title: Indexed Database API 3.0
Shortname: IndexedDB
Abstract: This document defines APIs for a database of records holding
simple values and hierarchical objects. Each record consists of a key
and some value. Moreover, the database maintains indexes over records
it stores. An application developer directly uses an API to locate
records either by their key or by using an index. A query language can
be layered on this API. An indexed database can be implemented using a
persistent B-tree data structure.
Status: ED
Previous Version: https://www.w3.org/TR/IndexedDB/
ED: https://w3c.github.io/IndexedDB/
TR: https://www.w3.org/TR/IndexedDB-3/
Level: 3
Editor: Ali Alabbas, Microsoft Corp. https://microsoft.com, alia@microsoft.com
Editor: Joshua Bell, Google Inc. https://google.com, jsbell@google.com
Group: webplatform
Test Suite: https://github.com/web-platform-tests/wpt/tree/master/IndexedDB
Favicon: logo-db.png
Complain About: accidental-2119 yes
Markup Shorthands: css no, markdown yes
</pre>
<pre class=link-defaults>
spec:html; type:dfn; for:/; text:task queue
</pre>
<pre class=anchors>
spec: html; urlPrefix: https://html.spec.whatwg.org/multipage/
urlPrefix: dom.html
type: interface
text: Document; url: document
spec: ecma262; urlPrefix: https://tc39.github.io/ecma262/
type: dfn
url: sec-algorithm-conventions
text: !
text: ?
text: abrupt completion; url: sec-completion-record-specification-type
text: ReturnIfAbrupt; url: sec-returnifabrupt
text: IdentifierName; url: prod-IdentifierName
text: Type; url: sec-ecmascript-data-types-and-values
text: HasOwnProperty; url: sec-hasownproperty
text: Get; url: sec-get-o-p
text: CreateDataProperty; url: sec-createdataproperty
text: ToLength; url: sec-tolength
text: ToString; url: sec-tostring
text: IsArray; url: sec-isarray
text: String; url: sec-terms-and-definitions-string-type
text: Number; url: sec-terms-and-definitions-number-type
text: RegExp; url: sec-regexp-regular-expression-objects
text: Date; url: sec-date-objects
text: Object; url: sec-object-objects
text: TypeError; url: sec-native-error-types-used-in-this-standard-typeerror
text: Array; url: sec-array-objects
text: ArrayBuffer; url: sec-arraybuffer-objects
text: Uint8Array; url: sec-typedarray-objects
text: Promise; url: sec-promise-objects
text: Realm; url: realm
text: current Realm; url: current-realm
text: Array.prototype.sort; url: sec-array.prototype.sort
text: Record; url: sec-list-and-record-specification-type
spec: webidl; urlPrefix: https://heycam.github.io/webidl/
type: dfn
text: sequence<DOMString>; url: idl-sequence
text: sequence<any>; url: idl-sequence
</pre>
<style>
/* Default ED/WD stylesheets set "both"; not needed for logo floated right */
div.head h1 { clear: left; }
table.props {
border-collapse: collapse;
border-style: hidden hidden none hidden;
}
table.props thead, table.props tbody {
border-bottom: solid;
}
table.props td, table.props th {
border-bottom: solid thin;
border-left: solid;
border-right: solid;
padding: 0.5em;
text-align: left;
vertical-align: top;
}
dl.domintro dt {
font-family: Menlo, Consolas, "DejaVu Sans Mono", Monaco, monospace;
padding-top: 0.5em;
padding-bottom: 1em;
}
dl.domintro dt a {
color: inherit; border-bottom-style: none;
}
dl.domintro dt code {
font-size: inherit;
}
</style>
This is the Third Edition of Indexed Database API.
The [First Edition](https://www.w3.org/TR/2015/REC-IndexedDB-20150108/)
became a W3C Recommendation on 8 January 2015.
The [Second Edition](https://www.w3.org/TR/2018/REC-IndexedDB-2-20180130/)
became a W3C Recommendation on 30 January 2018.
<!-- ============================================================ -->
# Introduction # {#introduction}
<!-- ============================================================ -->
User agents need to store large numbers of objects locally in order to
satisfy off-line data requirements of Web applications. [[WEBSTORAGE]]
is useful for storing pairs of keys and their corresponding values.
However, it does not provide in-order retrieval of keys, efficient
searching over values, or storage of duplicate values for a key.
This specification provides a concrete API to perform advanced
key-value data management that is at the heart of most sophisticated
query processors. It does so by using transactional databases to store
keys and their corresponding values (one or more per key), and
providing a means of traversing keys in a deterministic order. This is
often implemented through the use of persistent B-tree data structures
that are considered efficient for insertion and deletion as well as
in-order traversal of very large numbers of data records.
<aside class=example id=example-open-connection>
In the following example, the API is used to access a "library"
database that holds books stored by their "isbn" attribute.
Additionally, an index is maintained on the "title" attribute of the
objects stored in the object store. This index can be used to look up
books by title, and enforces a uniqueness constraint. Another index is
maintained on the "author" attribute of the objects, and can be used
to look up books by author.
A connection to the database is opened. If the "library" database did
not already exist, it is created and an event handler creates the
object store and indexes. Finally, the opened connection is saved for
use in subsequent examples.
```js
var request = indexedDB.open("library");
request.onupgradeneeded = function() {
// The database did not previously exist, so create object stores and indexes.
var db = request.result;
var store = db.createObjectStore("books", {keyPath: "isbn"});
var titleIndex = store.createIndex("by_title", "title", {unique: true});
var authorIndex = store.createIndex("by_author", "author");
// Populate with initial data.
store.put({title: "Quarry Memories", author: "Fred", isbn: 123456});
store.put({title: "Water Buffaloes", author: "Fred", isbn: 234567});
store.put({title: "Bedrock Nights", author: "Barney", isbn: 345678});
};
request.onsuccess = function() {
db = request.result;
};
```
The following example populates the database using a transaction.
```js
var tx = db.transaction("books", "readwrite");
var store = tx.objectStore("books");
store.put({title: "Quarry Memories", author: "Fred", isbn: 123456});
store.put({title: "Water Buffaloes", author: "Fred", isbn: 234567});
store.put({title: "Bedrock Nights", author: "Barney", isbn: 345678});
tx.oncomplete = function() {
// All requests have succeeded and the transaction has committed.
};
```
The following example looks up a single book in the database by title
using an index.
```js
var tx = db.transaction("books", "readonly");
var store = tx.objectStore("books");
var index = store.index("by_title");
var request = index.get("Bedrock Nights");
request.onsuccess = function() {
var matching = request.result;
if (matching !== undefined) {
// A match was found.
report(matching.isbn, matching.title, matching.author);
} else {
// No match was found.
report(null);
}
};
```
The following example looks up all books in the database by author
using an index and a cursor.
```js
var tx = db.transaction("books", "readonly");
var store = tx.objectStore("books");
var index = store.index("by_author");
var request = index.openCursor(IDBKeyRange.only("Fred"));
request.onsuccess = function() {
var cursor = request.result;
if (cursor) {
// Called for each matching record.
report(cursor.value.isbn, cursor.value.title, cursor.value.author);
cursor.continue();
} else {
// No more matching records.
report(null);
}
};
```
The following example shows how errors could be handled when a request
fails.
```js
var tx = db.transaction("books", "readwrite");
var store = tx.objectStore("books");
var request = store.put({title: "Water Buffaloes", author: "Slate", isbn: 987654});
request.onerror = function(event) {
// The uniqueness constraint of the "by_title" index failed.
report(request.error);
// Could call event.preventDefault() to prevent the transaction from aborting.
};
tx.onabort = function() {
// Otherwise the transaction will automatically abort due the failed request.
report(tx.error);
};
```
The database connection can be closed when it is no longer needed.
```js
db.close();
```
In the future, the database might have grown to contain other object
stores and indexes. The following example shows one way to handle
migrating from an older version of the database.
```js
var request = indexedDB.open("library", 3); // Request version 3.
request.onupgradeneeded = function(event) {
var db = request.result;
if (event.oldVersion < 1) {
// Version 1 is the first version of the database.
var store = db.createObjectStore("books", {keyPath: "isbn"});
var titleIndex = store.createIndex("by_title", "title", {unique: true});
var authorIndex = store.createIndex("by_author", "author");
}
if (event.oldVersion < 2) {
// Version 2 introduces a new index of books by year.
var bookStore = request.transaction.objectStore("books");
var yearIndex = bookStore.createIndex("by_year", "year");
}
if (event.oldVersion < 3) {
// Version 3 introduces a new object store for magazines with two indexes.
var magazines = db.createObjectStore("magazines");
var publisherIndex = magazines.createIndex("by_publisher", "publisher");
var frequencyIndex = magazines.createIndex("by_frequency", "frequency");
}
};
request.onsuccess = function() {
db = request.result; // db.version will be 3.
};
```
</aside>
<aside class=example id=handling-versionchange>
A single database can be used by multiple clients (pages and workers)
simultaneously &mdash; transactions ensure they don't clash while reading and writing.
If a new client wants to upgrade the database (via the "<code>[=upgradeneeded=]</code>"
event), it cannot do so until all other clients close their connection to the
current version of the database.
To avoid blocking a new client from upgrading, clients can listen for the
[=connection/version change event=]. This fires when another client is wanting to upgrade the
database. To allow this to continue, react to the "`versionchange`" event by doing
something that ultimately closes this client's [=/connection=] to the database.
One way of doing this is to reload the page:
```js
db.onversionchange = function() {
// First, save any unsaved data:
saveUnsavedData().then(function() {
// If the document isn't being actively used, it could be appropriate to reload
// the page without the user's interaction.
if (!document.hasFocus()) {
location.reload();
// Reloading will close the database, and also reload with the new JavaScript
// and database definitions.
} else {
// If the document has focus, it can be too disruptive to reload the page.
// Maybe ask the user to do it manually:
displayMessage("Please reload this page for the latest version.");
}
});
};
function saveUnsavedData() {
// How you do this depends on your app.
}
function displayMessage() {
// Show a non-modal message to the user.
}
```
Another way is to call the [=/connection=]'s {{IDBDatabase/close()}} method. However, you need to make
sure your app is aware of this, as subsequent attempts to access the database
will fail.
```js
db.onversionchange = function() {
saveUnsavedData().then(function() {
db.close();
stopUsingTheDatabase();
});
};
function stopUsingTheDatabase() {
// Put the app into a state where it no longer uses the database.
}
```
The new client (the one attempting the upgrade) can use the "`blocked`" event to
detect if other clients are preventing the upgrade from happening. The "`blocked`"
event fires if other clients still hold a connection to the database after their
"`versionchange`" events have fired.
```js
var request = indexedDB.open("library", 4); // Request version 4.
var blockedTimeout;
request.onblocked = function() {
// Give the other clients time to save data asynchronously.
blockedTimeout = setTimeout(function() {
displayMessage("Upgrade blocked - Please close other tabs displaying this site.");
}, 1000);
};
request.onupgradeneeded = function(event) {
clearTimeout(blockedTimeout);
hideMessage();
// ...
};
function hideMessage() {
// Hide a previously displayed message.
}
```
The user will only see the above message if another client fails to disconnect
from the database. Ideally the user will never see this.
</aside>
<!-- ============================================================ -->
# Constructs # {#constructs}
<!-- ============================================================ -->
A <dfn>name</dfn> is a string equivalent to a {{DOMString}};
that is, an arbitrary sequence of 16-bit code units of any length,
including the empty string. [=/Names=] are always compared as
opaque sequences of 16-bit code units.
<aside class=note>
As a result, [=/name=] comparison is sensitive to variations in case
as well as other minor variations such as normalization form, the
inclusion or omission of controls, and other variations in Unicode
text. [[Charmod-Norm]]
If an implementation uses a storage mechanism which does not support
arbitrary strings, the implementation can use an escaping mechanism
or something similar to map the provided name to a string that it
can store.
</aside>
A <dfn>sorted name list</dfn> is a list containing [=/names=]
sorted in ascending order by 16-bit code unit.
<details class=note>
<summary>Details</summary>
<p>This matches the [=Array.prototype.sort=] on an [=Array=] of
[=Strings=]. This ordering compares the 16-bit code units in each
string, producing a highly efficient, consistent, and deterministic
sort order. The resulting list will not match any particular
alphabet or lexicographical order, particularly for code points
represented by a surrogate pair.</p>
</details>
<!-- ============================================================ -->
## Database ## {#database-construct}
<!-- ============================================================ -->
Each [=/origin=] has an associated set of [=databases=]. A
<dfn>database</dfn> has zero or more [=/object stores=] which
hold the data stored in the database.
<div dfn-for=database>
A [=database=] has a <dfn>name</dfn> which identifies it within a
specific [=/origin=]. The name is a [=/name=],
and stays constant for the lifetime of the database.
A [=database=] has a <dfn>version</dfn>. When a database is first
created, its [=database/version=] is 0 (zero).
<aside class=note>
Each [=database=] has one version at a time; a [=database=] can't
exist in multiple versions at once. The only way to change the
version is using an [=/upgrade transaction=].
</aside>
A [=database=] has at most one associated <dfn>upgrade transaction</dfn>,
which is either null or an [=/upgrade transaction=], and is initially null.
</div>
<!-- ============================================================ -->
### Database Connection ### {#database-connection}
<!-- ============================================================ -->
Script does not interact with [=databases=] directly. Instead,
script has indirect access via a <dfn lt="connection|connected">connection</dfn>.
A [=/connection=] object can be used to manipulate the objects of
that [=database=]. It is also the only way to obtain a
[=/transaction=] for that [=database=].
The act of opening a [=database=] creates a [=/connection=].
There may be multiple [=/connections=] to a given [=database=] at
any given time.
A [=/connection=] can only access [=databases=] associated with the
[=/origin=] of the global scope from which the [=/connection=] is
opened.
<aside class=note>
This is not affected by changes to the {{Document}}'s
{{Document/domain}}.
</aside>
<div dfn-for=connection>
A [=/connection=] has a <dfn>version</dfn>, which is set when
the [=/connection=] is created. It remains constant for the
lifetime of the [=/connection=] unless an <a data-lt="abort
an upgrade transaction">upgrade is aborted</a>, in which
case it is set to the previous version of the [=database=]. Once
the [=/connection=] is closed the
[=connection/version=] does not change.
Each connection has a <dfn>close pending flag</dfn> which is initially
unset.
When a [=/connection=] is initially created it is in an opened
state. The connection can be <dfn>closed</dfn> through several means.
If the execution context where the [=/connection=] was created is
destroyed (for example due to the user navigating away from that
page), the connection is closed. The connection can also be closed
explicitly using the steps to [=close a database connection=]. When
the connection is closed the [=close pending flag=] is always set if
it hasn't already been.
A [=/connection=] may be closed by a user agent in exceptional
circumstances, for example due to loss of access to the file system, a
permission change, or clearing of the origin's storage. If this occurs
the user agent must run the steps to [=close a database
connection=] with the [=/connection=] and with the |forced flag| set.
A [=/connection=] has an <dfn>object store set</dfn>, which is
initialized to the set of [=/object stores=] in the associated
[=database=] when the [=/connection=] is created. The contents of the
set will remain constant except when an [=/upgrade transaction=] is
running.
A [=/connection=]'s [=get the parent=] algorithm returns
null.
A <dfn>version change event</dfn> will be fired at an open
[=/connection=] if an attempt is made to upgrade or delete the
[=database=]. This gives the [=/connection=] the opportunity to close
to allow the upgrade or delete to proceed.
</div>
<!-- ============================================================ -->
## Object Store ## {#object-store-construct}
<!-- ============================================================ -->
An <dfn>object store</dfn> is the primary storage mechanism for
storing data in a [=database=].
<div dfn-for=object-store>
Each database has a set of [=/object stores=]. The set of [=/object
stores=] can be changed, but only using an [=/upgrade transaction=],
i.e. in response to an <code>[=upgradeneeded=]</code> event. When a
new database is created it doesn't contain any [=/object stores=].
An [=/object store=] has a <dfn>list of records</dfn> which hold the
data stored in the object store. Each <dfn>record</dfn> consists of a
[=/key=] and a [=/value=]. The list is sorted according to key in
[=ascending=] order. There can never be multiple records in a given object
store with the same key.
An [=/object store=] has a <dfn>name</dfn>, which is a [=/name=].
At any one time, the name is unique
within the [=database=] to which it belongs.
An [=/object store=] optionally has a <dfn>key path</dfn>. If the
object store has a key path it is said to use <dfn>in-line keys</dfn>.
Otherwise it is said to use <dfn>out-of-line keys</dfn>.
An [=/object store=] optionally has a [=key generator=].
An object store can derive a [=/key=] for a [=object-store/record=] from
one of three sources:
1. A [=key generator=]. A key generator generates a monotonically
increasing numbers every time a key is needed.
1. Keys can be derived via a [=object-store/key path=].
1. Keys can also be explicitly specified when a [=/value=] is stored
in the object store.
</div>
<!-- ============================================================ -->
### Object Store Handle ### {#object-store-handle-construct}
<!-- ============================================================ -->
Script does not interact with [=/object stores=] directly. Instead,
within a [=/transaction=], script has indirect access via an
<dfn>object store handle</dfn>.
<div dfn-for=object-store-handle>
An [=/object store handle=] has an associated <dfn>object store</dfn>
and an associated <dfn>transaction</dfn>. Multiple handles may be
associated with the same [=/object store=] in different
[=/transactions=], but there must be only one [=/object store handle=]
associated with a particular [=/object store=] within a
[=/transaction=].
An [=/object store handle=] has an <dfn>index set</dfn>, which is
initialized to the set of [=/indexes=] that reference the associated
[=object-store-handle/object store=] when the [=/object store handle=]
is created. The contents of the set will remain constant except when
an [=/upgrade transaction=] is running.
An [=/object store handle=] has a <dfn>name</dfn>, which is
initialized to the [=object-store/name=] of the associated
[=object-store-handle/object store=] when the [=/object store handle=]
is created. The name will remain constant except when an [=/upgrade
transaction=] is running.
</div>
<!-- ============================================================ -->
## Values ## {#value-construct}
<!-- ============================================================ -->
Each record is associated with a <dfn>value</dfn>. User agents must
support any [=serializable object=]. This includes simple types
such as [=String=] primitive values and [=Date=] objects as well as
[=Object=] and [=Array=] instances, {{File}} objects, {{Blob}}
objects, {{ImageData}} objects, and so on. Record [=/values=] are
stored and retrieved by value rather than by reference; later changes
to a value have no effect on the record stored in the database.
Record [=/values=] are [=/Records=] output by the
<a abstract-op>StructuredSerializeForStorage</a> operation.
<!-- ============================================================ -->
## Keys ## {#key-construct}
<!-- ============================================================ -->
In order to efficiently retrieve [=object-store/records=] stored in an indexed
database, each [=object-store/record=] is organized according to its
<dfn>key</dfn>.
<div dfn-for=key>
A [=/key=] has an associated <dfn>type</dfn> which is one of:
*number*,
*date*,
*string*,
*binary*,
or
*array*.
A [=/key=] also has an associated <dfn>value</dfn>, which will
be either:
an {{unrestricted double}} if type is *number* or *date*,
a {{DOMString}} if type is *string*,
a list of {{octet}}s if type is *binary*,
or a list of other [=/keys=] if type is *array*.
</div>
An ECMAScript [[!ECMA-262]] value can be converted to a [=/key=] by
following the steps to [=convert a value to a key=].
<aside class=note>
The following ECMAScript types are valid keys:
* [=Number=] primitive values, except NaN. This includes Infinity
and -Infinity.
* [=Date=] objects, except where the \[[DateValue]]
internal slot is NaN.
* [=String=] primitive values.
* [=ArrayBuffer=] objects (or views on buffers such as
[=Uint8Array=]).
* [=Array=] objects, where every item is defined, is itself a valid
key, and does not directly or indirectly contain itself. This
includes empty arrays. Arrays can contain other arrays.
Attempting to convert other ECMAScript values to a [=/key=]
will fail.
</aside>
An <dfn>array key</dfn> is a [=/key=] with [=key/type=] *array*.
The <dfn>subkeys</dfn> of an [=array key=] are the members of the
[=array key=]'s [=key/value=] list.
<div class=algorithm>
To <dfn>compare two keys</dfn> |a| and |b|, run these steps:
1. Let |ta| be the [=key/type=] of |a|.
1. Let |tb| be the [=key/type=] of |b|.
1. If |ta| is *array* and |tb| is *binary*, *string*,
*date* or *number*, return 1.
1. If |tb| is *array* and |ta| is *binary*, *string*,
*date* or *number*, return -1.
1. If |ta| is *binary* and |tb| is *string*, *date* or
*number*, return 1.
1. If |tb| is *binary* and |ta| is *string*, *date* or
*number*, return -1.
1. If |ta| is *string* and |tb| is *date* or *number*,
return 1.
1. If |tb| is *string* and |ta| is *date* or *number*,
return -1.
1. If |ta| is *date* and |tb| is *number*, return 1.
1. If |tb| is *date* and |ta| is *number*, return -1.
1. Assert: |ta| and |tb| are equal.
1. Let |va| be the [=key/value=] of |a|.
1. Let |vb| be the [=key/value=] of |b|.
1. Switch on |ta|:
<dl class=switch>
<dt>*number*</dt>
<dt>*date*</dt>
<dd>
1. If |va| is greater than |vb|, then return 1.
1. If |va| is less than |vb|, then return -1.
1. Return 0.
</dd>
<dt>*string*</dt>
<dd>
1. Let |length| be the lesser of |va|'s length and |vb|'s length.
1. Let |i| be 0.
1. While |i| is less than |length|, then:
1. Let |u| be the code unit of |va| at index |i|.
1. Let |v| be the code unit of |vb| at index |i|.
1. If |u| is greater than |v| then return 1.
1. If |u| is less than |v| then return -1.
1. Increase |i| by 1.
1. If |va|'s length is greater than |vb|'s length, then return 1.
1. If |va|'s length is less than |vb|'s length, then return -1.
1. Return 0.
</dd>
<dt>*binary*</dt>
<dd>
1. Let |length| be the lesser of |va|'s length and |vb|'s length.
1. Let |i| be 0.
1. While |i| is less than |length|, then:
1. Let |u| be the {{octet}} in |va| at index |i|.
1. Let |v| be the {{octet}} in |vb| at index |i|.
1. If |u| is greater than |v| then return 1.
1. If |u| is less than |v| then return -1.
1. Increase |i| by 1.
1. If |va|'s length is greater than |vb|'s length, then return 1.
1. If |va|'s length is less than |vb|'s length, then return -1.
1. Return 0.
</dd>
<dt>*array*</dt>
<dd>
1. Let |length| be the lesser of |va|'s length and |vb|'s length.
1. Let |i| be 0.
1. While |i| is less than |length|, then:
1. Let |u| be the [=/key=] in |va| at index |i|.
1. Let |v| be the [=/key=] in |vb| at index |i|.
1. Let |c| be the result of recursively running the steps to [=compare two keys=] with |u| and |v|.
1. If |c| is not 0, return |c|.
1. Increase |i| by 1.
1. If |va|'s length is greater than |vb|'s length, then return 1.
1. If |va|'s length is less than |vb|'s length, then return -1.
1. Return 0.
</dd>
</dl>
</div>
The [=/key=] |a| is <dfn lt="greater than|ascending">greater than</dfn> the [=/key=] |b| if the
result of running the steps to [=compare two keys=] with |a| and |b|
is 1.
The [=/key=] |a| is <dfn>less than</dfn> the [=/key=] |b| if the
result of running the steps to [=compare two keys=] with |a| and |b|
is -1.
The [=/key=] |a| is <dfn>equal to</dfn> the [=/key=] |b| if the result
of running the steps to [=compare two keys=] with |a| and |b| is 0.
<aside class=note>
As a result of the above rules, negative infinity is the lowest
possible value for a [=/key=].
*Number* keys are less than *date* keys.
*Date* keys are less than *string* keys.
*String* keys are less than *binary* keys.
*Binary* keys are less than *array* keys.
There is no highest possible [=/key=] value.
This is because an array of any candidate highest [=/key=]
followed by another [=/key=] is even higher.
</aside>
<aside class=note>
Members of *binary* keys are compared as unsigned {{octet}} values
(in the range [0, 255]) rather than signed {{byte}} values (in the range
[-128, 127]).
</aside>
<!-- ============================================================ -->
## Key Path ## {#key-path-construct}
<!-- ============================================================ -->
A <dfn>key path</dfn> is a string or list of strings
that defines how to extract a [=/key=]
from a [=/value=]. A <dfn>valid key path</dfn> is one of:
* An empty string.
* An <dfn>identifier</dfn>, which is a string matching the
[=IdentifierName=] production from the ECMAScript Language
Specification [[!ECMA-262]].
* A string consisting of two or more [=identifiers=] separated
by periods (U+002E FULL STOP).
* A non-empty list containing only strings
conforming to the above requirements.
<aside class=note>
Spaces are not allowed within a key path.
</aside>
[=/Key path=] values can only be accessed from properties explicitly
copied by <a abstract-op>StructuredSerializeForStorage</a>, as well as the
following type-specific properties:
<table class=props>
<tr><th>Type</th><th>Properties</th></tr>
<tr><td>{{Blob}}</td><td>{{Blob/size}}, {{Blob/type}}</td></tr>
<tr><td>{{File}}</td><td>{{File/name}}, {{File/lastModified}}, `lastModifiedDate`</td></tr>
<tr><td>[=Array=]</td><td>`length`</td></tr>
<tr><td>[=String=]</td><td>`length`</td></tr>
</table>
<!-- ============================================================ -->
## Index ## {#index-construct}
<!-- ============================================================ -->
It is sometimes useful to retrieve [=object-store/records=] in an
[=/object store=] through other means than their
[=/key=]. An <dfn id=index-concept>index</dfn> allows looking up
[=object-store/records=] in an [=/object store=] using properties of the
[=/values=] in the [=/object stores=] [=object-store/records=].
<div dfn-for=index>
An index is a specialized persistent key-value storage and has a <dfn
lt="referenced|references">referenced</dfn> [=/object store=]. The
index has a <dfn>list of records</dfn> which hold the data stored in
the index. The <dfn>records</dfn> in an index are automatically populated
whenever records in the [=referenced=] object store are inserted,
updated or deleted. There can be several [=/indexes=] referencing the
same [=/object store=], in which changes to the object store cause all
such indexes to get updated.
The <dfn>values</dfn> in the index's [=index/records=] are always values of [=/keys=]
in the index's [=referenced=] object store. The <dfn>keys</dfn> are derived from
the referenced object store's [=/values=] using a <dfn>key path</dfn>.
If a given [=object-store/record=] with key |X| in the object store referenced by
the index has the value |A|, and <a data-lt="extract a key from a
value using a key path">evaluating</a> the index's [=index/key path=]
on |A| yields the result |Y|, then the index will contain a record
with key |Y| and value |X|.
<aside class=example id=example-index-entries>
For example, if an index's [=referenced=] object store contains a
record with the key `123` and the value `{ name:
"Alice", title: "CEO" }`, and the index's [=index/key path=]
is "`name`" then the index would contain a record with
the key "`Alice`" and the value `123`.
</aside>
Records in an index are said to have a <dfn>referenced value</dfn>.
This is the value of the record in the index's referenced object store
which has a key equal to the index's record's value. So in the example
above, the record in the index whose [=index/key=] is |Y| and value is |X| has a
[=referenced value=] of |A|.
<aside class=example id=example-index-referenced-values>
In the preceding example, the record in the index with key
"`Alice`" and value `123` would have a
[=referenced value=] of `{ name: "Alice", title: "CEO"
}`.
</aside>
<aside class=note>
Each record in an index references one and only one record in the
index's [=referenced=] object store. However there can be multiple
records in an index which reference the same record in the object
store. And there can also be no records in an index which reference
a given record in an object store.
</aside>
The [=object-store/records=] in an index are always sorted according to the
[=object-store/record=]'s key. However unlike object stores, a given index can
contain multiple records with the same key. Such records are
additionally sorted according to the [=/index=]'s [=object-store/record=]'s value
(meaning the key of the record in the referenced [=/object store=]).
An [=/index=] has a <dfn>name</dfn>, which is a [=/name=].
At any one time, the name is
unique within index's [=referenced=] [=/object store=].
An [=/index=] has a <dfn>unique flag</dfn>. When this flag is
set, the index enforces that no two [=object-store/records=] in the index has
the same key. If a [=object-store/record=] in the index's referenced object
store is attempted to be inserted or modified such that evaluating the
index's key path on the records new value yields a result which
already exists in the index, then the attempted modification to the
object store fails.
An [=/index=] has a <dfn>multiEntry flag</dfn>. This flag affects how
the index behaves when the result of evaluating the index's
[=index/key path=] yields an [=array key=]. If the [=multiEntry flag=]
is unset, then a single [=object-store/record=] whose [=/key=] is an [=array key=]
is added to the index. If the [=multiEntry flag=] is true, then the
one [=object-store/record=] is added to the index for each of the [=subkeys=].
</div>
<!-- ============================================================ -->
### Index Handle ### {#index-handle-construct}
<!-- ============================================================ -->
Script does not interact with [=/indexes=] directly. Instead, within
a [=/transaction=], script has indirect access via an <dfn>index
handle</dfn>.
<div dfn-for=index-handle>
An [=index handle=] has an associated <dfn>index</dfn> and an
associated <dfn>object store handle</dfn>. The <dfn>transaction</dfn>
of an [=index handle=] is the [=object-store-handle/transaction=] of
its associated [=/object store handle=]. Multiple handles may be
associated with the same [=/index=] in different [=/transactions=],
but there must be only one [=index handle=] associated with a
particular [=/index=] within a [=/transaction=].
An [=index handle=] has a <dfn>name</dfn>, which is initialized to the
[=index/name=] of the associated [=index-handle/index=] when the
[=index handle=] is created. The name will remain constant except when
an [=/upgrade transaction=] is running.
</div>
<!-- ============================================================ -->
## Transactions ## {#transaction-construct}
<!-- ============================================================ -->
A <dfn id=transaction-concept>Transaction</dfn> is used to interact
with the data in a [=database=]. Whenever data is read or written
to the database it is done by using a [=/transaction=].
<div dfn-for=transaction>
[=/Transactions=] offer some protection from application and system
failures. A [=/transaction=] may be used to store multiple data
records or to conditionally modify certain data records. A
[=/transaction=] represents an atomic and durable set of data access
and data mutation operations.
All transactions are created through a [=/connection=], which is the
transaction's <dfn>connection</dfn>.
A [=/transaction=] has a <dfn>scope</dfn> that determines the
[=/object stores=] with which the transaction may interact. A
transaction's scope remains fixed for the lifetime of that
transaction.
A [=/transaction=] has a <dfn>mode</dfn> that determines which types
of interactions can be performed upon that transaction. The [=transaction/mode=]
is set when the transaction is created and remains fixed for the life
of the transaction. A [=/transaction=]'s [=transaction/mode=] is one of the
following:
<dl>
<dt>{{"readonly"}}</dt>
<dd>
The transaction is only allowed to read data. No modifications can
be done by this type of transaction. This has the advantage that
several [=read-only transactions=] can run at the same time even
if their [=transaction/scopes=] are overlapping, i.e. if they are using the
same object stores. This type of transaction can be created any
time once a database has been opened.
</dd>
<dt>{{"readwrite"}}</dt>
<dd>
The transaction is allowed to read, modify and delete data from
existing object stores. However object stores and indexes can't be
added or removed. Multiple {{"readwrite"}} transactions
can't run at the same time if their [=transaction/scopes=] are overlapping
since that would mean that they can modify each other's data in
the middle of the transaction. This type of transaction can be
created any time once a database has been opened.
</dd>
<dt>{{"versionchange"}}</dt>
<dd>
The transaction is allowed to read, modify and delete data from
existing object stores, and can also create and remove object
stores and indexes. It is the only type of transaction that can do
so. This type of transaction can't be manually created, but
instead is created automatically when an
<code>[=upgradeneeded=]</code> event is fired.
</dd>
</dl>
A [=/transaction=] has an <dfn>active flag</dfn>, which determines
if new [=requests=] can be made against the transaction. A
transaction is said to be <dfn>active</dfn> if its [=transaction/active flag=]
is set.
A [=/transaction=] optionally has a <dfn>cleanup event loop</dfn>
which is an [=event loop=].
A [=/transaction=] has a <dfn>request list</dfn> of [=requests=]
which have been made against the transaction.
A [=/transaction=] has a <dfn>error</dfn> which is set if the
[=/transaction=] is [=transaction/aborted=].
A [=/transaction=]'s [=get the parent=] algorithm returns the
transaction's [=transaction/connection=].
A <dfn>read-only transaction</dfn> is
a [=/transaction=] with [=transaction/mode=] {{"readonly"}}.
A <dfn>read/write transaction</dfn>
is a [=/transaction=] with [=transaction/mode=] {{"readwrite"}}.
<!-- ============================================================ -->
### Transaction Lifetime ### {#transaction-lifetime-concept}
<!-- ============================================================ -->
Transactions are expected to be short lived. This is encouraged by the
<a for=transaction lt=commit>automatic committing</a> functionality
described below.
<aside class=note>
Authors can still cause transactions to run for a long time;
however, this usage pattern is not advised as it can lead to a poor
user experience.
</aside>
The <dfn>lifetime</dfn> of a
[=/transaction=] is as follows:
1. A transaction is <dfn>created</dfn> with a [=transaction/scope=] and a [=transaction/mode=].
When a transaction is created its [=transaction/active flag=] is initially set.
1. The implementation must allow [=requests=] to be [=request/placed=]
against the transaction whenever the [=transaction/active flag=] is set. This
is the case even if the transaction has not yet been [=transaction/started=].
Until the transaction is [=transaction/started=] the implementation must not
execute these requests; however, the implementation must keep
track of the [=requests=] and their order. Requests may be placed
against a transaction only while that transaction is [=transaction/active=].
If an attempt is made to place a request against a transaction
when that transaction is not [=transaction/active=], the implementation must
reject the attempt by throwing a "{{TransactionInactiveError}}" {{DOMException}}.
1. Once an implementation is able to enforce the constraints defined
for the transaction [=transaction/scope=] and [=transaction/mode=], defined below, the
implementation must [=queue a task=] to <dfn
lt="start|started">start</dfn> the transaction asynchronously.
1. Once the transaction has been [=transaction/started=] the implementation can
start executing the [=requests=] placed against the transaction.
Unless otherwise defined, requests must be executed in the order
in which they were made against the transaction. Likewise, their
results must be returned in the order the requests were placed
against a specific transaction. There is no guarantee about the
order that results from requests in different transactions are
returned. Similarly, the transaction [=transaction/modes=] ensure that two
requests placed against different transactions can execute in any
order without affecting what resulting data is stored in the
database.
1. A transaction can be <dfn lt="abort|aborting|aborted">aborted</dfn>
at any time before it is [=transaction/finished=], even if the transaction
isn't currently [=transaction/active=] or hasn't yet [=transaction/started=]. When a
transaction is aborted the implementation must undo (roll back)
any changes that were made to the [=database=] during that
transaction. This includes both changes to the contents of
[=/object stores=] as well as additions and removals of [=/object
stores=] and [=/indexes=].
1. A transaction can fail for reasons not tied to a particular
[=request=]. For example due to IO errors when committing the
transaction, or due to running into a quota limit where the
implementation can't tie exceeding the quota to a partcular
request. In this case the implementation must run the steps to
[=abort a transaction=] using the transaction as |transaction|
and the appropriate error type as |error|. For example if quota
was exceeded then a "{{QuotaExceededError}}" {{DOMException}} should be used as
|error|, and if an IO error happened, an "{{UnknownError}}" {{DOMException}} should be
used as |error|.
1. When a transaction has been started and it can no longer become
[=transaction/active=], the implementation must attempt to <dfn
lt="commit|committing|committed">commit</dfn> it, as long as the
transaction has not been [=transaction/aborted=]. This usually happens after
all requests placed against the transaction have been executed and
their returned results handled, and no new requests have been
placed against the transaction. When a transaction is committed,
the implementation must atomically write any changes to the
[=database=] made by requests placed against the transaction. That
is, either all of the changes must be written, or if an error
occurs, such as a disk write error, the implementation must not
write any of the changes to the database. If such an error occurs,
the implementation must [=transaction/abort=] the transaction by following the
steps to [=abort a transaction=], otherwise it must
[=transaction/commit=] the transaction by following the steps to
[=commit a transaction=].
1. When a transaction is [=transaction/committed=] or [=transaction/aborted=], it
is said to be <dfn lt="finish|finished">finished</dfn>. If a
transaction can't be finished, for example due to the
implementation crashing or the user taking some explicit action to
cancel it, the implementation must [=transaction/abort=] the transaction.
The following constraints define when a [=/transaction=] can be
[=transaction/started=]:
* Any number of [=read-only transactions=] are allowed to run
concurrently, even if the transaction's [=transaction/scope=] overlap and
include the same [=/object stores=]. As long as a [=read-only
transaction=] is running, the data that the implementation returns
through [=requests=] created with that transaction must remain
constant. That is, two requests to read the same piece of data
must yield the same result both for the case when data is found
and the result is that data, and for the case when data is not
found and a lack of data is indicated.
<aside class=note>
There are a number of ways that an implementation can ensure
this. The implementation could prevent any <a>read/write
transaction</a>, whose scope overlaps the scope of the
[=read-only transaction=], from starting until the
[=read-only transaction=] finishes. Or the implementation
could allow the [=read-only transaction=] to see a snapshot
of the contents of the [=/object stores=] which is taken when
the [=read-only transaction=] started.
</aside>
* Similarly, implementations must ensure that a <a>read/write
transaction</a> is only affected by changes to [=/object
stores=] that are made using the transaction itself. For
example, the implementation must ensure that another transaction
does not modify the contents of [=/object stores=] in the
<a>read/write transaction</a>'s [=transaction/scope=]. The implementation
must also ensure that if the <a>read/write transaction</a>
completes successfully, the changes written to [=/object
stores=] using the transaction can be committed to the
[=database=] without merge conflicts. An implementation must
not abort a transaction due to merge conflicts.
* If multiple <a>read/write transactions</a> are attempting to access
the same object store (i.e. if they have overlapping [=transaction/scope=]),
the transaction that was [=transaction/created=] first must be the transaction
which gets access to the object store first. Due to the
requirements in the previous paragraph, this also means that it is
the only transaction which has access to the object store until
the transaction is [=transaction/finished=].
* Any transaction [=transaction/created=] after a <a>read/write transaction</a>
must see the changes written by the <a>read/write transaction</a>.
So if a <a>read/write transaction</a>, A, is created, and later
another transaction B, is created, and the two transactions have
overlapping [=transaction/scopes=], then B must see any changes made to any
[=/object stores=] that are part of that overlapping [=transaction/scope=].
Due to the requirements in the previous paragraph, this also means
that the B transaction does not have access to any [=/object
stores=] in that overlapping [=transaction/scope=] until the A transaction is
[=transaction/finished=].
<aside class=note>
Generally speaking, the above requirements mean that any
transaction which has an overlapping scope with a <a>read/write
transaction</a> and which was created after that <a>read/write
transaction</a>, can't run in parallel with that <a>read/write
transaction</a>.
</aside>
* User agents must ensure a reasonable level of fairness across
transactions to prevent starvation. For example, if multiple
[=read-only transactions=] are started one after another the
implementation must not indefinitely prevent a pending
<a>read/write transaction</a> from [=transaction/starting=].
</div>
To <dfn export>cleanup Indexed Database transactions</dfn>, run these steps.
They will return true if any transactions were cleaned up, or false otherwise.
<div class=algorithm>
1. If there are no [=/transactions=] with [=transaction/cleanup
event loop=] matching the current [=event loop=], return false.
1. For each [=/transaction=] with [=transaction/cleanup event loop=]
matching the current [=event loop=]:
1. Unset the [=/transaction=]'s [=transaction/active flag=].
1. Clear the [=/transaction=]'s [=transaction/cleanup event loop=].
1. Return true.
</div>
<aside class=note>
This behavior is invoked by [[HTML]]. It ensures that
[=/transactions=] created by a script call
to {{IDBDatabase/transaction()}} are deactivated once the task that
invoked the script has completed. The steps are run at most once for
each [=/transaction=].
</aside>
<!-- ============================================================ -->
### Upgrade Transactions ### {#upgrade-transaction-construct}
<!-- ============================================================ -->
An <dfn>upgrade transaction</dfn> is a [=/transaction=] with [=transaction/mode=]
{{"versionchange"}}.
An [=/upgrade transaction=] is automatically created when running the
steps to [=run an upgrade transaction=] after a [=/connection=]
is opened to a [=/database=], if a [=database/version=] greater than
the current [=database/version=] is specified. This [=/transaction=]
will be active inside the <code>[=upgradeneeded=]</code> event
handler.
<aside class=note>
An [=/upgrade transaction=] enables the creation, renaming, and
deletion of [=/object stores=] and [=/indexes=] in a [=/database=].
An [=/upgrade transaction=] is exclusive. The steps to [=open a
database=] ensure that only one [=/connection=] to the database is
open when an [=/upgrade transaction=] is running.
The <code>[=upgradeneeded=]</code> event isn't fired, and thus the
[=/upgrade transaction=] isn't started, until all other
[=/connections=] to the same [=/database=] are closed. This ensures
that all previous transactions are [=transaction/finished=]. As long
as an [=/upgrade transaction=] is running, attempts to open more
[=/connections=] to the same [=/database=] are delayed, and any
attempts to use the same [=/connection=] to start additional
transactions by calling {{IDBDatabase/transaction()}} will throw an
exception. Thus [=/upgrade transactions=] not only ensure that no
other transactions are running concurrently, but also ensure that no
new transactions are queued against the same [=/database=] as long
as the transaction is running.
This ensures that once an [=/upgrade transaction=] is complete, the
set of [=/object stores=] and [=/indexes=] in a [=/database=] remain
constant for the lifetime of all subsequent [=/connections=] and
[=/transactions=].
</aside>
<!-- ============================================================ -->
## Requests ## {#request-construct}
<!-- ============================================================ -->
Each asynchronous operation on a [=database=] is done using a <dfn>request</dfn>. Every request represents one
operation.
<div dfn-for=request>
A [=request=] has a <dfn>done flag</dfn> which is initially unset.
A [=request=] has a <dfn>source</dfn> object.
A [=request=] has a <dfn>result</dfn> and an <dfn>error</dfn>, neither
of which are accessible until the [=request/done flag=] is set.
A [=request=] has a <dfn>transaction</dfn> which is initially null.
This will be set when a request is <dfn>placed</dfn> against a
[=/transaction=] using the steps to [=asynchronously execute a
request=].
When a request is made, a new [=request=] is returned with its [=request/done
flag=] unset. If a request completes successfully, the [=request/done flag=]
is set, the [=request/result=] is set to the result of the request,
and an event with type `success` is fired at the
[=request=].
If an error occurs while performing the operation, the [=request/done flag=]
is set, the [=request/error=] is set to the error, and an event with
type `error` is fired at the request.
A [=request=]'s [=get the parent=] algorithm returns the request's
[=request/transaction=].
<aside class=note>
Requests are not typically re-used, but there are exceptions. When a
[=cursor=] is iterated, the success of the iteration is reported
on the same [=request=] object used to open the cursor. And when
an [=/upgrade transaction=] is necessary, the same [=open
request=] is used for both the <code>[=upgradeneeded=]</code>
event and final result of the open operation itself. In some cases,
the request's [=request/done flag=] will be unset then set again, and the
[=request/result=] can change or [=request/error=] could be set insead.
</aside>
<!-- ============================================================ -->
### Open Requests ### {#open-requests}
<!-- ============================================================ -->
An <dfn>open request</dfn> is a special type of [=request=] used
when opening a [=/connection=] or deleting a [=database=].
In addition to `success` and `error` events,
<dfn>`blocked`</dfn> and <dfn>`upgradeneeded`</dfn> may be fired at an [=open
request=] to indicate progress.
The [=request/source=] of an [=open request=]
is always null.
The [=request/transaction=] of an [=open request=] is null
unless an <code>[=upgradeneeded=]</code> event has been fired.
An [=open request=]'s [=get the parent=] algorithm returns null.
[=Open requests=] are processed in a <dfn>connection queue</dfn>.
The queue contains all [=open requests=] associated with an
[=/origin=] and a [=database/name=]. Requests added to the
[=connection queue=] processed in order and each request must run
to completion before the next request is processed. An open request
may be blocked on other [=/connections=], requiring those
connections to [=connection/close=] before the request can complete and allow
further requests to be processed.
<aside class=note>
A [=connection queue=] is not a [=task queue=] associated with
an [=event loop=], as the requests are processed outside any
specific [=/browsing context=]. The delivery of events to
completed [=open request=] still goes through a [=task queue=]
associated with the [=event loop=] of the context where the
request was made.
</aside>
</div>
<!-- ============================================================ -->
## Key Range ## {#range-construct}
<!-- ============================================================ -->
Records can be retrieved from [=/object stores=] and [=/indexes=]
using either [=/keys=] or [=key ranges=]. A <dfn>key range</dfn> is a
continuous interval over some data type used for keys.
A [=key range=] has an associated <dfn>lower bound</dfn> (null or a
[=/key=]).
A [=key range=] has an associated <dfn>upper bound</dfn> (null or a
[=/key=]).
A [=key range=] has an associated <dfn>lower open flag</dfn>.
Unless otherwise stated it is unset.
A [=key range=] has an associated <dfn>upper open flag</dfn>.
Unless otherwise stated it is unset.
A [=key range=] may have a [=lower bound=] [=equal to=] its
[=upper bound=]. A [=key range=] must not have a [=lower
bound=] [=greater than=] its [=upper bound=].
A [=key range=] <dfn>containing only</dfn> |key| has both
[=lower bound=] and [=upper bound=] equal to |key|.
A |key| is <dfn lt="in">in a key range</dfn> if both of the following
conditions are fulfilled:
* The [=lower bound=] is null, or it is [=less than=]
|key|, or it is both [=equal to=] |key| and
the [=lower open flag=] is unset.
* The [=upper bound=] is null, or it is [=greater than=]
|key|, or it is both [=equal to=] |key| and
the [=upper open flag=] is unset.
<aside class=note>
* If the [=lower open flag=] of a [=key range=] is unset, the
[=lower bound=] [=/key=] of the [=key range=] is included
in the range itself.
* If the [=lower open flag=] of a [=key range=] is set, the
[=lower bound=] [=/key=] of the [=key range=] is excluded
from the range itself.
* If the [=upper open flag=] of a [=key range=] is unset, the
[=upper bound=] [=/key=] of the [=key range=] is included
in the range itself.
* If the [=upper open flag=] of a [=key range=] is set, the
[=upper bound=] [=/key=] of the [=key range=] is excluded
from the range itself.
</aside>
An <dfn>unbounded key range</dfn> is a [=key range=] that has both
[=lower bound=] and [=upper bound=] equal to null. All
[=/keys=] are [=in=] an [=unbounded key
range=].
<div class=algorithm>
The steps to <dfn>convert a value to a key range</dfn> with
|value| and optional |null disallowed flag| are as
follows:
1. If |value| is a [=key range=], return |value|.
1. If |value| is undefined or is null, then [=throw=] a
"{{DataError}}" {{DOMException}} if |null disallowed flag| is set, or return an
[=unbounded key range=] otherwise.
1. Let |key| be the result of running the steps to [=convert
a value to a key=] with |value|. Rethrow any exceptions.
1. If |key| is invalid, [=throw=] a "{{DataError}}" {{DOMException}}.
1. Return a [=key range=] [=containing only=] |key|.
</div>
<!-- ============================================================ -->
## Cursor ## {#cursor-construct}
<!-- ============================================================ -->
A <dfn>cursor</dfn> is used to iterate over a range of records in an
[=/index=] or an [=/object store=] in a specific direction.
<div dfn-for=cursor>
A [=cursor=] has a <dfn>transaction</dfn>, the [=/transaction=]
that was [=transaction/active=] when the cursor was created.
A [=cursor=] has a <dfn>range</dfn> of records in either an
[=/index=] or an [=/object store=].
A [=cursor=] has a <dfn>source</dfn> that indicates which [=/index=]
or an [=/object store=] is associated with the records over which
the [=cursor=] is iterating.
A [=cursor=] has a <dfn>direction</dfn> that determines whether it
moves in monotonically increasing or decreasing order of the
[=object-store/record=] keys when iterated, and if it skips duplicated values
when iterating indexes. The direction of a cursor also determines if
the cursor initial position is at the start of its
[=cursor/source=] or at its end. A cursor's
[=cursor/direction=] is one of the following:
<dl>
<dt>{{"next"}}</dt>
<dd>
This direction causes the cursor to be opened at the start of the
[=cursor/source=]. When iterated, the [=cursor=] should yield all
records, including duplicates, in monotonically increasing order
of keys.
</dd>
<dt>{{"nextunique"}}</dt>
<dd>
This direction causes the cursor to be opened at the start of the
[=cursor/source=]. When iterated, the [=cursor=] should not yield
records with the same key, but otherwise yield all records, in
monotonically increasing order of keys. For every key with
duplicate values, only the first record is yielded. When the
[=cursor/source=] is an [=/object store=] or an [=/index=] with
the [=unique flag=] set, this direction has exactly the same
behavior as {{"next"}}.
</dd>
<dt>{{"prev"}}</dt>
<dd>
This direction causes the cursor to be opened at the end of the
[=cursor/source=]. When iterated, the [=cursor=] should yield all
records, including duplicates, in monotonically decreasing order
of keys.
</dd>
<dt>{{"prevunique"}}</dt>
<dd>
This direction causes the cursor to be opened at the end of the
[=cursor/source=]. When iterated, the [=cursor=] should not
yield records with the same key, but otherwise yield all records,
in monotonically decreasing order of keys. For every key with
duplicate values, only the first record is yielded. When the
[=cursor/source=] is an [=/object store=] or an
[=/index=] with the [=unique flag=] set, this direction
has exactly the same behavior as {{"prev"}}.
</dd>
</dl>
A [=cursor=] has a <dfn>position</dfn> within its range. It is
possible for the list of records which the cursor is iterating over to
change before the full [=cursor/range=] of the cursor has been iterated.
In order to handle this, cursors maintain their [=cursor/position=] not as
an index, but rather as a [=/key=] of the previously returned
record. For a forward iterating cursor, the next time the cursor is
asked to iterate to the next record it returns the record with the
lowest [=/key=] [=greater than=] the one previously
returned. For a backwards iterating cursor, the situation is opposite
and it returns the record with the highest [=/key=] [=less
than=] the one previously returned.
For cursors iterating indexes the situation is a little bit more
complicated since multiple records can have the same key and are
therefore also sorted by [=/value=]. When iterating indexes the
[=cursor=] also has an <dfn>object store position</dfn>, which
indicates the [=/value=] of the previously found [=object-store/record=] in
the index. Both [=cursor/position=] and the [=object store position=]
are used when finding the next appropriate record.
A [=cursor=] has a <dfn>key</dfn> and a <dfn>value</dfn> which
represent the [=/key=] and the [=/value=] of the last iterated
[=object-store/record=].
A [=cursor=] has a <dfn>got value flag</dfn>. When this flag unset,
the cursor is either in the process of loading the next value or it
has reached the end of its [=cursor/range=]. When it is set, it indicates
that the cursor is currently holding a value and that it is ready to
iterate to the next one.
If the [=cursor/source=] of a cursor is an [=/object store=], the
<dfn>effective object store</dfn> of the cursor is that object store
and the <dfn>effective key</dfn> of the cursor is the cursor's
[=cursor/position=]. If the [=cursor/source=] of a cursor is an [=/index=],
the [=effective object store=] of the cursor is that index's
[=referenced=] object store and the [=effective key=] is the cursor's
[=object store position=].
A [=cursor=] also has a <dfn>key only flag</dfn>, that indicates
whether the cursor's [=cursor/value=] is exposed via the API. Unless
stated otherwise it is unset.
</div>
<!-- ============================================================ -->
## Key Generators ## {#key-generator-construct}
<!-- ============================================================ -->
When a [=/object store=] is created it can be specified to use a
<dfn>key generator</dfn>. A key generator is used to generate keys
for records inserted into an object store if not otherwise specified.
<div dfn-for="key generator">
A [=key generator=] has a <dfn>current number</dfn>. The
[=key generator/current number=] is always a positive integer less
than or equal to 2<sup>53</sup> (9007199254740992) + 1. The initial value
of a [=key generator=]'s [=key generator/current number=] is 1, set
when the associated [=/object store=] is created. The
[=key generator/current number=] is incremented as keys are generated,
and may be updated to a specific value by using explicit keys.
</div>
<aside class=note>
Every object store that uses key generators uses a separate
generator. That is, interacting with one object store never affects
the key generator of any other object store.
</aside>
Modifying a key generator's [=key generator/current number=] is considered part
of a database operation. This means that if the operation fails
and the operation is reverted, the [=key generator/current number=] is
reverted to the value it had before the operation started. This
applies both to modifications that happen due to the [=key generator/current
number=] getting increased by 1 when the key generator is used,
and to modifications that happen due to a [=object-store/record=] being
stored with a key value specified in the call to store the
[=object-store/record=].
Likewise, if a [=/transaction=] is aborted, the [=key generator/current
number=] of the key generator for each [=/object store=] in
the transaction's [=transaction/scope=] is reverted to the value it had
before the [=/transaction=] was started.
The [=key generator/current number=] for a key generator never decreases, other
than as a result of database operations being reverted. Deleting a
[=object-store/record=] from an [=/object store=] never affects the
object store's key generator. Even clearing all records from an
object store, for example using the {{IDBObjectStore/clear()}} method, does not
affect the [=key generator/current number=] of the object store's key
generator.
When a [=object-store/record=] is stored and a [=/key=] is not specified
in the call to store the record, a key is generated.
<div class=algorithm>
To <dfn>generate a key</dfn> for an [=/object store=] |store|, run these steps:
1. Let |generator| be the [=key generator=] associated with |store|.
1. Let |key| be |generator|'s [=key generator/current number=].
1. If |key| is greater than 2<sup>53</sup> (9007199254740992), then return failure.
1. Increase |generator|'s [=key generator/current number=] by 1.
1. Return |key|.
</div>
When a [=object-store/record=] is stored and a [=/key=] is specified
in the call to store the record, the associated [=key generator=] may
be updated.
<div class=algorithm>
To <dfn>possibly update the key generator</dfn> for an [=/object store=] |store| with |key|,
run these steps:
1. If the [=key/type=] of |key| is not *number*, abort these steps.
1. Let |value| be the [=key/value=] of |key|.
1. Let |value| be the minimum of |value| and 2<sup>53</sup> (9007199254740992).
1. Let |value| be the largest integer not greater than |value|.
1. Let |generator| be the [=key generator=] associated with |store|.
1. If |value| is greater than or equal to |generator|'s [=key generator/current number=],
then set |generator|'s [=key generator/current number=] to |value| + 1.
</div>
<aside class=note>
A key can be specified both for object stores which use
[=in-line keys=], by setting the property on the stored value
which the object store's [=object-store/key path=] points to,
and for object stores which use [=out-of-line keys=], by passing
a key argument to the call to store the [=object-store/record=].
Only specified keys of [=key/type=] *number* can affect the
[=key generator/current number=] of the key generator. Keys of [=key/type=]
*date*, *array* (regardless of the other keys they
contain), *binary*, or *string* (regardless of whether
they could be parsed as numbers) have no effect on the [=key generator/current
number=] of the key generator. Keys of [=key/type=]
*number* with [=key/value=] less than 1 do not affect the
[=key generator/current number=] since they are always lower than the
[=key generator/current number=].
</aside>
When the [=key generator/current number=] of a key generator reaches above the
value 2<sup>53</sup> (9007199254740992) any subsequent attempts to use the
key generator to generate a new [=/key=] will result in a
"{{ConstraintError}}" {{DOMException}}. It is still possible to insert
[=object-store/records=] into the object store by specifying an explicit
key, however the only way to use a key generator again for such records
is to delete the object store and create a new one.
<aside class=note>
This limit arises because integers greater than 9007199254740992
cannot be uniquely represented as ECMAScript [=Numbers=].
As an example, `9007199254740992 + 1 === 9007199254740992`
in ECMAScript.
As long as key generators are used in a normal fashion this limit will
not be a problem. If you generate a new key 1000 times per
second day and night, you won't run into this limit for over
285000 years.
</aside>
A practical result of this is that the first key generated for an
object store is always 1 (unless a higher numeric key is inserted
first) and the key generated for an object store is always a positive
integer higher than the highest numeric key in the store. The same key
is never generated twice for the same object store unless a
transaction is rolled back.
<aside class=example id=example-key-generator>
Each object store gets its own key generator:
```js
store1 = db.createObjectStore("store1", { autoIncrement: true });
store1.put("a"); // Will get key 1
store2 = db.createObjectStore("store2", { autoIncrement: true });
store2.put("a"); // Will get key 1
store1.put("b"); // Will get key 2
store2.put("b"); // Will get key 2
```
If an insertion fails due to constraint violations or IO error, the
key generator is not updated.
```js
transaction.onerror = function(e) { e.preventDefault() };
store = db.createObjectStore("store1", { autoIncrement: true });
index = store.createIndex("index1", "ix", { unique: true });
store.put({ ix: "a"}); // Will get key 1
store.put({ ix: "a"}); // Will fail
store.put({ ix: "b"}); // Will get key 2
```
Removing items from an objectStore never affects the key generator.
Including when {{IDBObjectStore/clear()}} is called.
```js
store = db.createObjectStore("store1", { autoIncrement: true });
store.put("a"); // Will get key 1
store.delete(1);
store.put("b"); // Will get key 2
store.clear();
store.put("c"); // Will get key 3
store.delete(IDBKeyRange.lowerBound(0));
store.put("d"); // Will get key 4
```
Inserting an item with an explicit key affects the key generator if,
and only if, the key is numeric and higher than the last generated
key.
```js
store = db.createObjectStore("store1", { autoIncrement: true });
store.put("a"); // Will get key 1
store.put("b", 3); // Will use key 3
store.put("c"); // Will get key 4
store.put("d", -10); // Will use key -10
store.put("e"); // Will get key 5
store.put("f", 6.00001); // Will use key 6.0001
store.put("g"); // Will get key 7
store.put("f", 8.9999); // Will use key 8.9999
store.put("g"); // Will get key 9
store.put("h", "foo"); // Will use key "foo"
store.put("i"); // Will get key 10
store.put("j", [1000]); // Will use key [1000]
store.put("k"); // Will get key 11
// All of these would behave the same if the objectStore used a
// keyPath and the explicit key was passed inline in the object
```
Aborting a transaction rolls back any increases to the key generator
which happened during the transaction. This is to make all rollbacks
consistent since rollbacks that happen due to crash never has a chance
to commit the increased key generator value.
```js
db.createObjectStore("store", { autoIncrement: true });
trans1 = db.transaction(["store"], "readwrite");
store_t1 = trans1.objectStore("store");
store_t1.put("a"); // Will get key 1
store_t1.put("b"); // Will get key 2
trans1.abort();
trans2 = db.transaction(["store"], "readwrite");
store_t2 = trans2.objectStore("store");
store_t2.put("c"); // Will get key 1
store_t2.put("d"); // Will get key 2
```
</aside>
<aside class=example id=example-inline-keygen>
The following examples illustrate the different behaviors when trying
to use in-line [=/keys=] and [=key generators=] to save an object
to an [=/object store=].
If the following conditions are true:
* The [=/object store=] has a [=key generator=].
* There is no in-line value for the [=object-store/key path=]
property.
Then the value provided by the [=key generator=] is used to populate
the key value. In the example below the [=object-store/key path=] for
the object store is "`foo.bar`". The actual object has no
value for the `bar` property, `{ foo: {} }`.
When the object is saved in the [=/object store=] the `bar`
property is assigned a value of 1 because that is the next [=/key=]
generated by the [=key generator=].
```js
var store = db.createObjectStore("store", { keyPath: "foo.bar",
autoIncrement: true });
store.put({ foo: {} }).onsuccess = function(e) {
var key = e.target.result;
console.assert(key === 1);
};
```
If the following conditions are true:
* The [=/object store=] has a [=key generator=].
* There is a value for the [=object-store/key path=]
property.
Then the value associated with the [=object-store/key path=]
property is used. The auto-generated [=/key=] is not used. In the
example below the [=object-store/key path=] for the [=/object
store=] is "`foo.bar`". The actual object has a value of
10 for the `bar` property, `{ foo: { bar: 10}
}`. When the object is saved in the [=/object store=] the
`bar` property keeps its value of 10, because that is the
key value.
```js
var store = db.createObjectStore("store", { keyPath: "foo.bar",
autoIncrement: true });
store.put({ foo: { bar: 10 } }).onsuccess = function(e) {
var key = e.target.result;
console.assert(key === 10);
};
```
The following example illustrates the scenario when the specified
in-line [=/key=] is defined through a [=object-store/key
path=] but there is no property matching it. The value provided by
the [=key generator=] is then used to populate the key value and
the system is responsible for creating as many properties as it
requires to suffice the property dependencies on the hierarchy chain.
In the example below the [=object-store/key path=] for the
[=/object store=] is "`foo.bar.baz`". The actual
object has no value for the `foo` property, `{ zip: {}
}`. When the object is saved in the [=/object store=]
the `foo`, `bar`, and `baz`
properties are created each as a child of the other until a value for
`foo.bar.baz` can be assigned. The value for
`foo.bar.baz` is the next key generated by the object
store.
```js
var store = db.createObjectStore("store", { keyPath: "foo.bar.baz",
autoIncrement: true });
store.put({ zip: {} }).onsuccess = function(e) {
var key = e.target.result;
console.assert(key === 1);
store.get(key).onsuccess = function(e) {
var value = e.target.result;
// value will be: { zip: {}, foo: { bar: { baz: 1 } } }
console.assert(value.foo.bar.baz === 1);
};
};
```
Attempting to store a property on a primitive value will fail and
throw an error. In the first example below the [=object-store/key
path=] for the object store is "`foo`". The actual object
is a primitive with the value, `4`. Trying to define a
property on that primitive value fails. The same is true for arrays.
Properties are not allowed on an array. In the second example below,
the actual object is an array, `[10]`. Trying to define a
property on the array fails.
```js
var store = db.createObjectStore("store", { keyPath: "foo", autoIncrement: true });
// The key generation will attempt to create and store the key path
// property on this primitive.
store.put(4); // will throw DataError
// The key generation will attempt to create and store the key path
// property on this array.
store.put([10]); // will throw DataError
```
</aside>
<!-- ============================================================ -->
# Exceptions # {#exceptions}
<!-- ============================================================ -->
Each of the exceptions used in this document is a
{{DOMException}} with a specific type. The exception types and
properties such as legacy code value are defined in [[!WEBIDL]].
The table below lists the {{DOMException}}s used in this
document along with a description of the exception type's
usage.
<table class=props>
<tr>
<th>Type</th>
<th>Description</th>
</tr>
<tr>
<td>{{AbortError}}</td>
<td>A request was aborted.</td>
</tr>
<tr>
<td>{{ConstraintError}}</td>
<td>
A mutation operation in the transaction failed because a
constraint was not satisfied.
</td>
</tr>
<tr>
<td>{{DataCloneError}}</td>
<td>
The data being stored could not be cloned by the internal
structured cloning algorithm.
</td>
</tr>
<tr>
<td>{{DataError}}</td>
<td>Data provided to an operation does not meet requirements.</td>
</tr>
<tr>
<td>{{InvalidAccessError}}</td>
<td>An invalid operation was performed on an object.</td>
</tr>
<tr>
<td>{{InvalidStateError}}</td>
<td>
An operation was called on an object on which it is not allowed
or at a time when it is not allowed, or if a request is made on
a source object that has been deleted or removed.
</td>
</tr>
<tr>
<td>{{NotFoundError}}</td>
<td>
The operation failed because the requested database object could
not be found.
</td>
</tr>
<tr>
<td>{{QuotaExceededError}}</td>
<td>
The operation failed because there was not enough remaining
storage space, or the storage quota was reached and the user
declined to give more space to the database.
</td>
</tr>
<tr>
<td>{{SyntaxError}}</td>
<td>The keyPath argument contains an invalid key path.</td>
</tr>
<tr>
<td>{{ReadOnlyError}}</td>
<td>The mutating operation was attempted in a read-only transaction.</td>
</tr>
<tr>
<td>{{TransactionInactiveError}}</td>
<td>
A request was placed against a transaction which is currently
not active, or which is finished.
</td>
</tr>
<tr>
<td>{{UnknownError}}</td>
<td>
The operation failed for reasons unrelated to the database
itself and not covered by any other errors.
</td>
</tr>
<tr>
<td>{{VersionError}}</td>
<td>
An attempt was made to open a database using a lower version
than the existing version.
</td>
</tr>
</table>
<aside class=note>
Given that multiple Indexed DB operations can throw the same type of
error, and that a even single operation can throw the same type of
error for multiple reasons, implementations are encouraged to
provide more specific messages to enable developers to identify the
cause of errors.
</aside>
<!-- ============================================================ -->
# API # {#async-api}
<!-- ============================================================ -->
The API methods return without blocking the calling thread. All
asynchronous operations immediately return an {{IDBRequest}}
instance. This object does not initially contain any information about
the result of the operation. Once information becomes available, an
event is fired on the request and the information becomes available
through the properties of the {{IDBRequest}} instance.
The <span>task source</span> for these tasks is the <dfn export>database
access task source</dfn>.
<!-- ============================================================ -->
## The {{IDBRequest}} interface ## {#request-api}
<!-- ============================================================ -->
The {{IDBRequest}} interface provides the means to access results of
asynchronous requests to [=databases=] and [=database=] objects using
[=event handler IDL attributes=] [[!HTML]].
Every method for making asynchronous requests returns an
{{IDBRequest}} object that communicates back to the requesting
application through events. This design means that any number of
requests can be active on any [=database=] at a time.
<aside class=example id=example-async-requests>
In the following example, we open a [=database=] asynchronously.
Various event handlers are registered for responding to various
situations.
```js
var request = indexedDB.open('AddressBook', 15);
request.onsuccess = function(evt) {...};
request.onerror = function(evt) {...};
```
</aside>
<xmp class=idl>
[Exposed=(Window,Worker)]
interface IDBRequest : EventTarget {
readonly attribute any result;
readonly attribute DOMException? error;
readonly attribute (IDBObjectStore or IDBIndex or IDBCursor)? source;
readonly attribute IDBTransaction? transaction;
readonly attribute IDBRequestReadyState readyState;
// Event handlers:
attribute EventHandler onsuccess;
attribute EventHandler onerror;
};
enum IDBRequestReadyState {
"pending",
"done"
};
</xmp>
<div class=note>
<dl class=domintro>
<dt><var>request</var> . {{IDBRequest/result}}</dt>
<dd>
When a request is completed, returns the [=request/result=],
or `undefined` if the request failed. Throws a
"{{InvalidStateError}}" {{DOMException}} if the request is still pending.
</dd>
<dt><var>request</var> . {{IDBRequest/error}}</dt>
<dd>
When a request is completed, returns the [=request/error=] (a
{{DOMException}}), or null if the request succeeded. Throws
a "{{InvalidStateError}}" {{DOMException}} if the request is still pending.
</dd>
<dt><var>request</var> . {{IDBRequest/source}}</dt>
<dd>
Returns the {{IDBObjectStore}}, {{IDBIndex}}, or {{IDBCursor}}
the request was made against, or null if is was an [=open
request=].
</dd>
<dt><var>request</var> . {{IDBRequest/transaction}}</dt>
<dd>
Returns the {{IDBTransaction}} the request was made within.
If this as an [=open request=], then it returns an
[=/upgrade transaction=] while it is running, or null otherwise.
</dd>
<dt><var>request</var> . {{IDBRequest/readyState}}</dt>
<dd>
Returns {{"pending"}} until a request is complete,
then returns {{"done"}}.
</dd>
</dl>
</div>
The <dfn attribute for=IDBRequest>result</dfn> attribute's getter must
[=throw=] an "{{InvalidStateError}}" {{DOMException}} if the [=request/done flag=] is
unset. Otherwise, the attribute's getter must return the
[=request/result=] of the request, or undefined if the
request resulted in an error.
The <dfn attribute for=IDBRequest>error</dfn> attribute's getter must
[=throw=] an "{{InvalidStateError}}" {{DOMException}} if the [=request/done flag=] is unset.
Otherwise, the attribute's getter must return the [=request/error=] of
the request, or null if no error occurred.
The <dfn attribute for=IDBRequest>source</dfn> attribute's getter must
return the [=request/source=] of the [=request=], or null if no
[=request/source=] is set.
The <dfn attribute for=IDBRequest>transaction</dfn> attribute's getter
must return the [=request/transaction=] of the [=request=]. This
property can be null for certain requests, such as for [=requests=]
returned from {{IDBFactory/open()}}.
The <dfn attribute for=IDBRequest>readyState</dfn> attribute's getter
must return {{"pending"}} if the [=request/done flag=] is unset, and
{{"done"}} otherwise.
The <dfn attribute for=IDBRequest>onsuccess</dfn> attribute is the
event handler for the `success` event.
The <dfn attribute for=IDBRequest>onerror</dfn> attribute is the event
handler for the `error` event.
Methods on {{IDBDatabase}} that return a [=open request=] use an
extended interface to allow listening to the
<code>[=request/blocked=]</code> event and
<code>[=upgradeneeded=]</code> event.
<xmp class=idl>
[Exposed=(Window,Worker)]
interface IDBOpenDBRequest : IDBRequest {
// Event handlers:
attribute EventHandler onblocked;
attribute EventHandler onupgradeneeded;
};
</xmp>
The <dfn attribute for=IDBOpenDBRequest>onblocked</dfn> attribute is
the event handler for the <code>[=request/blocked=]</code> event.
The <dfn attribute for=IDBOpenDBRequest>onupgradeneeded</dfn>
attribute is the event handler for the
<code>[=upgradeneeded=]</code> event.
<!-- ============================================================ -->
## Event interfaces ## {#events}
<!-- ============================================================ -->
This specification fires events with the following custom interfaces:
<xmp class=idl>
[Exposed=(Window,Worker),
Constructor(DOMString type, optional IDBVersionChangeEventInit eventInitDict)]
interface IDBVersionChangeEvent : Event {
readonly attribute unsigned long long oldVersion;
readonly attribute unsigned long long? newVersion;
};
dictionary IDBVersionChangeEventInit : EventInit {
unsigned long long oldVersion = 0;
unsigned long long? newVersion = null;
};
</xmp>
The <dfn attribute for=IDBVersionChangeEvent>oldVersion</dfn>
attribute getter returns the previous version of the database.
The <dfn attribute for=IDBVersionChangeEvent>newVersion</dfn>
attribute getter returns the new version of the database, or null if
the database is being deleted. See the steps to [=run an upgrade
transaction=].
Events are constructed as defined in [[DOM#constructing-events]].
<div class=algorithm>
To <dfn>fire a version change event</dfn> named |e| at |target| given
|oldVersion| and |newVersion|, run these steps:
1. Let |event| be the result of [=creating an event=] using
{{IDBVersionChangeEvent}}.
1. Set |event|'s {{Event/type}} attribute to |e|.
1. Set |event|'s {{Event/bubbles}} and {{Event/cancelable}} attributes to false.
1. Set |event|'s {{IDBVersionChangeEvent/oldVersion}} attribute to |oldVersion|.
1. Set |event|'s {{IDBVersionChangeEvent/newVersion}} attribute to |newVersion|.
1. Let |legacyOutputDidListenersThrowFlag| be unset.
1. [=Dispatch=] |event| at |target| with |legacyOutputDidListenersThrowFlag|.
1. Return |legacyOutputDidListenersThrowFlag|.
<aside class=note>
The return value of this algorithm is not always used.
</aside>
</div>
<!-- ============================================================ -->
## The {{IDBFactory}} interface ## {#factory-interface}
<!-- ============================================================ -->
[=Database=] objects are accessed through methods on the
{{IDBFactory}} interface. A single object implementing this
interface is present in the global scope of environments that support
Indexed DB operations.
<xmp class=idl id=global-scope>
partial interface mixin WindowOrWorkerGlobalScope {
[SameObject] readonly attribute IDBFactory indexedDB;
};
</xmp>
The <dfn attribute for=WindowOrWorkerGlobalScope>indexedDB</dfn>
attribute provides applications a mechanism for accessing capabilities
of indexed databases.
<xmp class=idl>
[Exposed=(Window,Worker)]
interface IDBFactory {
[NewObject] IDBOpenDBRequest open(DOMString name,
optional [EnforceRange] unsigned long long version);
[NewObject] IDBOpenDBRequest deleteDatabase(DOMString name);
short cmp(any first, any second);
};
</xmp>
<div class=note>
<dl class=domintro>
<dt><var>request</var> = indexedDB .
{{IDBFactory/open()|open}}(<var>name</var>)</dt>
<dd>
Attempts to open a [=/connection=] to the named [=/database=]
with the current version, or 1 if it does not already exist.
If the request is successful |request|'s
{{IDBRequest/result}} will be the [=/connection=].
</dd>
<dt><var>request</var> = indexedDB .
{{IDBFactory/open()|open}}(<var>name</var>, <var>version</var>)</dt>
<dd>
Attempts to open a [=/connection=] to the named [=/database=]
with the specified version. If the database already exists
with a lower version and there are open [=/connections=]
that don't close in response to a
`versionchange` event, the request will be
[=request/blocked=] until all they close, then an upgrade
will occur. If the database already exists with a higher
version the request will fail. If the request is
successful |request|'s {{IDBRequest/result}} will
be the [=/connection=].
</dd>
<dt><var>request</var> = indexedDB .
{{IDBFactory/deleteDatabase()|deleteDatabase}}(<var>name</var>)</dt>
<dd>
Attempts to delete the named [=/database=]. If the
database already exists and there are open
[=/connections=] that don't close in response to a
`versionchange` event, the request will be
[=request/blocked=] until all they close. If the request
is successful |request|'s {{IDBRequest/result}}
will be null.
</dd>
</dl>
</div>
<div class=algorithm>
The <dfn method for=IDBFactory>open(|name|, |version|)</dfn> method,
when invoked, must run these steps:
1. If |version| is 0 (zero), [=throw=] a [=TypeError=].
1. Let |origin| be the [=/origin=] of the global scope used
to access this {{IDBFactory}}.
1. If |origin| is an [=opaque origin=], [=throw=] a
"{{SecurityError}}" {{DOMException}} and abort these steps.
1. Let |request| be a new [=open request=].
1. Run these steps [=in parallel=]:
1. Let |result| be the result of running the steps to
[=open a database=], with |origin|,
|name|, |version| if given and undefined
otherwise, and |request|.
<details class=note>
<summary>What happens if |version| is not given?</summary>
If |version| is not given and a [=database=]
with that name already exists, a connection will be opened
without changing the [=database/version=]. If
|version| is not given and no [=database=] with
that name exists, a new [=database=] will be created with
[=database/version=] equal to 1.
</details>
1. [=Queue a task=] to run these steps:
1. If |result| is an error,
set |request|'s [=request/result=] to undefined,
set |request|'s [=request/error=] to |result|,
set |request|'s [=request/done flag=],
and [=fire an event=] named
`error` at |request| with its
{{Event/bubbles}} and {{Event/cancelable}} attributes initialized to true.
1. Otherwise,
set |request|'s [=request/result=] to |result|,
set |request|'s [=request/done flag=],
and [=fire an event=] named
`success` at |request|. If the steps
above resulted in an [=/upgrade transaction=] being run,
then firing the "`success`" event must be done
after the [=/upgrade transaction=] completes.
<aside class=note>
The last requirement is to ensure that in case another
version upgrade is about to happen, the success event is
fired on the connection first so that the script gets a
chance to register a listener for the
`versionchange` event.
</aside>
<details class=note>
<summary>
Why aren't the steps to [=fire a success event=] or
[=fire an error event=] used?
</summary>
There is no transaction associated with the request (at
this point), so those steps &mdash; which activate an
associated transaction before dispatch and deactivate
the transaction after dispatch &mdash; do not apply.
</details>
1. Return a new {{IDBOpenDBRequest}} object for |request|.
</div>
<div class=algorithm>
The <dfn method for=IDBFactory>deleteDatabase(|name|)</dfn> method,
when invoked, must run these steps:
1. Let |origin| be the [=/origin=] of the global scope used
to access this {{IDBFactory}}.
1. If |origin| is an [=opaque origin=], [=throw=] a
"{{SecurityError}}" {{DOMException}} and abort these steps.
1. Let |request| be a new [=open request=].
1. Run these steps [=in parallel=]:
1. Let |result| be the result of running the steps to
[=delete a database=], with |origin|,
|name|, and |request|.
1. [=Queue a task=] to run these steps:
1. If |result| is an error,
set |request|'s [=request/error=] to |result|,
set |request|'s [=request/done flag=],
and [=fire an event=]
named `error` at |request| with
its {{Event/bubbles}} and {{Event/cancelable}} attributes initialized to true.
1. Otherwise,
set |request|'s [=request/result=] to undefined,
set |request|'s [=request/done flag=],
and [=fire a version change event=] named
`success` at [=request=] with |result| and
null.
<details class=note>
<summary>
Why aren't the steps to [=fire a success event=] or
[=fire an error event=] used?
</summary>
There is no transaction associated with the request, so
those steps &mdash; which activate an associated
transaction before dispatch and deactivate the
transaction after dispatch &mdash; do not apply.
Also, the `success` event here is a
{{IDBVersionChangeEvent}} which includes the
{{IDBVersionChangeEvent/oldVersion}} and
{{IDBVersionChangeEvent/newVersion}} details.
</details>
1. Return a new {{IDBOpenDBRequest}} object for |request|.
</div>
<div class=note>
<dl class=domintro>
<dt><var>result</var> = indexedDB .
{{IDBFactory/cmp()|cmp}}(<var>key1</var>, <var>key2</var>)</dt>
<dd>
Compares two values as [=/keys=]. Returns -1 if
|key1| precedes |key2|, 1 if
|key2| precedes |key1|, and 0 if
the keys are equal.
Throws a "{{DataError}}" {{DOMException}} if either input is not a valid [=/key=].
</dd>
</dl>
</div>
<div class=algorithm>
The <dfn method for=IDBFactory>cmp(|first|, |second|)</dfn> method,
when invoked, must run these steps:
1. Let |a| be the result of running the steps to [=convert a
value to a key=] with |first|. Rethrow any exceptions.
1. If |a| is invalid, [=throw=] a "{{DataError}}" {{DOMException}}.
1. Let |b| be the result of running the steps to [=convert a
value to a key=] with |second|. Rethrow any exceptions.
1. If |b| is invalid, [=throw=] a "{{DataError}}" {{DOMException}}.
1. Return the results of running the steps to [=compare two keys=]
with |a| and |b|.
</div>
<!-- ============================================================ -->
## The {{IDBDatabase}} interface ## {#database-interface}
<!-- ============================================================ -->
The {{IDBDatabase}}
interface represents a [=/connection=] to a [=database=].
An {{IDBDatabase}} object must not be garbage collected if its
associated [=/connection=]'s [=close pending flag=] is unset and it
has one or more event listeners registers whose type is one of
`abort`, `error`, or `versionchange`.
If an {{IDBDatabase}} object is garbage collected, the associated
[=/connection=] must be [=connection/closed=].
<xmp class=idl>
[Exposed=(Window,Worker)]
interface IDBDatabase : EventTarget {
readonly attribute DOMString name;
readonly attribute unsigned long long version;
readonly attribute DOMStringList objectStoreNames;
[NewObject] IDBTransaction transaction((DOMString or sequence<DOMString>) storeNames,
optional IDBTransactionMode mode = "readonly");
void close();
[NewObject] IDBObjectStore createObjectStore(DOMString name,
optional IDBObjectStoreParameters options);
void deleteObjectStore(DOMString name);
// Event handlers:
attribute EventHandler onabort;
attribute EventHandler onclose;
attribute EventHandler onerror;
attribute EventHandler onversionchange;
};
dictionary IDBObjectStoreParameters {
(DOMString or sequence<DOMString>)? keyPath = null;
boolean autoIncrement = false;
};
</xmp>
<div class=note>
<dl class=domintro>
<dt><var>connection</var> . {{IDBDatabase/name}}</dt>
<dd>
Returns the [=database/name=] of the database.
</dd>
<dt><var>connection</var> . {{IDBDatabase/version}}</dt>
<dd>
Returns the [=database/version=] of the database.
</dd>
</dl>
</div>
The <dfn attribute for=IDBDatabase>name</dfn> attribute's getter must
return the [=database/name=] of the [=connected=]
[=database=]. The attribute must return this name even if the
[=close pending flag=] is set on the [=/connection=]. In
other words, the value of this attribute stays constant for the
lifetime of the {{IDBDatabase}} instance.
The <dfn attribute for=IDBDatabase>version</dfn> attribute's getter
must return this [=/connection=]'s
[=connection/version=].
<details class=note>
<summary>
Is this the same as the [=/database=]'s [=database/version=]?
</summary>
As long as the [=/connection=] is open, this is the same as the
connected [=database=]'s [=database/version=]. But once the
[=/connection=] has [=connection/closed=], this attribute will not
reflect changes made with a later [=/upgrade transaction=].
</details>
<div class=note>
<dl class=domintro>
<dt><var>connection</var> . {{IDBDatabase/objectStoreNames}}</dt>
<dd>
Returns a list of the names of [=/object stores=] in the database.
</dd>
<dt><var>store</var> = <var>connection</var> .
{{IDBDatabase/createObjectStore()|createObjectStore}}(<var>name</var>
[, <var>options</var>])</dt>
<dd>
Creates a new [=/object store=] with the given |name| and |options|
and returns a new {{IDBObjectStore}}.
Throws a "{{InvalidStateError}}" {{DOMException}} if not called within an
[=/upgrade transaction=].
</dd>
<dt><var>connection</var> .
{{IDBDatabase/deleteObjectStore()|deleteObjectStore}}(<var>name</var>)</dt>
<dd>
Deletes the [=/object store=] with the given |name|.
Throws a "{{InvalidStateError}}" {{DOMException}} if not called within an
[=/upgrade transaction=].
</dd>
</dl>
</div>
The <dfn attribute for=IDBDatabase>objectStoreNames</dfn> attribute's
getter must return a {{DOMStringList}} associated with a [=sorted name list=] of the [=object-store/names=] of
the [=/object stores=] in this [=/connection=]'s [=object store set=].
<details class=note>
<summary>
Is this the same as the [=database=]'s [=/object store=]
[=object-store/names=]?
</summary>
As long as the [=/connection=] is open, this is the same as the
connected [=database=]'s [=/object store=] [=object-store/names=].
But once the [=/connection=] has [=connection/closed=], this attribute
will not reflect changes made with a later [=/upgrade transaction=].
</details>
<div class=algorithm>
The <dfn method for=IDBDatabase>createObjectStore(|name|,
|options|)</dfn> method, when invoked, must run these steps:
1. Let |database| be the [=database=] associated with this
[=/connection=].
1. Let |transaction| be |database|'s [=database/upgrade transaction=]
if it is not null, or [=throw=] an "{{InvalidStateError}}"
{{DOMException}} otherwise.
1. If |transaction| is not [=transaction/active=], [=throw=] a
"{{TransactionInactiveError}}" {{DOMException}}.
1. Let |keyPath| be |options|'s {{IDBObjectStoreParameters/keyPath}}
member if it is not undefined or null, or null otherwise.
1. If |keyPath| is not null and is not a [=valid key
path=], [=throw=] a "{{SyntaxError}}" {{DOMException}}.
1. If an [=/object store=] [=object-store/named=] |name| already
exists in |database| [=throw=] a "{{ConstraintError}}" {{DOMException}}.
1. Let |autoIncrement| be set if |options|'s
{{IDBObjectStoreParameters/autoIncrement}} member is true, or
unset otherwise.
1. If |autoIncrement| is set and |keyPath| is an empty string or any
sequence (empty or otherwise), [=throw=] an
"{{InvalidAccessError}}" {{DOMException}}.
1. Let |store| be a new [=/object store=] in
|database|. Set the created [=/object store=]'s
[=object-store/name=] to |name|. If
|autoIncrement| is set, then the created [=/object
store=] uses a [=key generator=]. If |keyPath| is
not null, set the created [=/object store=]'s
[=object-store/key path=] to |keyPath|.
1. Return a new [=/object store handle=] associated with
|store| and |transaction|.
</div>
This method creates and returns a new [=/object store=] with the given
name in the [=connected=] [=database=]. Note that this method must
only be called from within an [=/upgrade transaction=].
This method synchronously modifies the
{{IDBDatabase/objectStoreNames}} property on the {{IDBDatabase}}
instance on which it was called.
In some implementations it is possible for the implementation to run
into problems after queuing a task to create the [=/object store=]
after the {{createObjectStore()}} method has returned. For example in
implementations where metadata about the newly created [=/object
store=] is inserted into the database asynchronously, or where the
implementation might need to ask the user for permission for quota
reasons. Such implementations must still create and return an
{{IDBObjectStore}} object, and once the implementation determines that
creating the [=/object store=] has failed, it must abort the
transaction using the steps to [=abort a transaction=] using the
appropriate error. For example if creating the [=/object store=]
failed due to quota reasons, a "{{QuotaExceededError}}" {{DOMException}} must be used as
error.
<div class=algorithm>
The <dfn method for=IDBDatabase>deleteObjectStore(|name|)</dfn>
method, when invoked, must run these steps:
1. Let |database| be the [=database=] associated with this
[=/connection=].
1. Let |transaction| be |database|'s [=database/upgrade transaction=]
if it is not null, or [=throw=] an "{{InvalidStateError}}"
{{DOMException}} otherwise.
1. If |transaction| is not [=transaction/active=], [=throw=] a
"{{TransactionInactiveError}}" {{DOMException}}.
1. Let |store| be the [=/object store=]
[=object-store/named=] |name| in |database|,
or [=throw=] a "{{NotFoundError}}" {{DOMException}} if none.
1. Remove |store| from this [=/connection=]'s [=object
store set=].
1. If there is an [=/object store handle=] associated with
|store| and |transaction|, remove all entries from its
[=object-store-handle/index set=].
1. Destroy |store|.
</div>
This method destroys the [=/object store=] with the given name in the
[=connected=] [=database=]. Note that this method must only be called
from within an [=/upgrade transaction=].
This method synchronously modifies the
{{IDBDatabase/objectStoreNames}} property on the {{IDBDatabase}}
instance on which it was called.
<div class=note>
<dl class=domintro>
<dt><var>transaction</var> = <var>connection</var> .
{{IDBDatabase/transaction()|transaction}}(<var>scope</var>
[, <var>mode</var> = "readonly"])</dt>
<dd>
Returns a new [=/transaction=] with the given |mode|
({{"readonly"}} or {{"readwrite"}})
and |scope| which can be a single [=/object store=]
[=object-store/name=] or an array of
[=object-store/names=].
</dd>
<dt><var>connection</var> . {{IDBDatabase/close()|close}}()</dt>
<dd>
Closes the [=/connection=] once all running [=/transactions=]
have finished.
</dd>
</dl>
</div>
<div class=algorithm>
The <dfn method for=IDBDatabase>transaction(|storeNames|,
|mode|)</dfn> method, when invoked, must run these steps:
1. If a running [=/upgrade transaction=] is associated with the [=/connection=],
[=throw=] an "{{InvalidStateError}}" {{DOMException}}.
1. If the [=/connection=]'s
[=close pending flag=] is set, [=throw=] an
"{{InvalidStateError}}" {{DOMException}}.
1. Let |scope| be the set of unique strings in |storeNames| if it is a
sequence, or a set containing one string equal to |storeNames|
otherwise.
1. If any string in |scope| is not the name of an [=/object
store=] in the [=connected=] [=database=], [=throw=] a
"{{NotFoundError}}" {{DOMException}}.
1. If |scope| is empty, [=throw=] an "{{InvalidAccessError}}" {{DOMException}}.
1. If |mode| is not {{"readonly"}} or {{"readwrite"}},
[=throw=] a [=TypeError=].
1. Let |transaction| be a newly [=transaction/created=] [=/transaction=] with
|connection|, |mode| and the set of [=/object stores=] named in
|scope|.
1. Set |transaction|'s [=transaction/cleanup event loop=] to the
current [=event loop=].
1. Return an {{IDBTransaction}} object representing |transaction|.
</div>
<aside class=note>
The created |transaction| will follow the [=transaction/lifetime=]
rules.
</aside>
<div class=algorithm>
The <dfn method for=IDBDatabase>close()</dfn> method, when invoked,
must run these steps:
1. Run the steps to [=close a database connection=] with this
[=/connection=].
</div>
The <dfn attribute for=IDBDatabase>onabort</dfn> attribute is the
event handler for the `abort` event.
The <dfn attribute for=IDBDatabase>onclose</dfn> attribute is the
event handler for the `close` event.
The <dfn attribute for=IDBDatabase>onerror</dfn> attribute is the
event handler for the `error` event.
The <dfn attribute for=IDBDatabase>onversionchange</dfn> attribute is
the event handler for the `versionchange` event.
<!-- ============================================================ -->
## The {{IDBObjectStore}} interface ## {#object-store-interface}
<!-- ============================================================ -->
The {{IDBObjectStore}}
interface represents an [=/object store handle=].
<xmp class=idl>
[Exposed=(Window,Worker)]
interface IDBObjectStore {
attribute DOMString name;
readonly attribute any keyPath;
readonly attribute DOMStringList indexNames;
[SameObject] readonly attribute IDBTransaction transaction;
readonly attribute boolean autoIncrement;
[NewObject] IDBRequest put(any value, optional any key);
[NewObject] IDBRequest add(any value, optional any key);
[NewObject] IDBRequest delete(any query);
[NewObject] IDBRequest clear();
[NewObject] IDBRequest get(any query);
[NewObject] IDBRequest getKey(any query);
[NewObject] IDBRequest getAll(optional any query,
optional [EnforceRange] unsigned long count);
[NewObject] IDBRequest getAllKeys(optional any query,
optional [EnforceRange] unsigned long count);
[NewObject] IDBRequest count(optional any query);
[NewObject] IDBRequest openCursor(optional any query,
optional IDBCursorDirection direction = "next");
[NewObject] IDBRequest openKeyCursor(optional any query,
optional IDBCursorDirection direction = "next");
IDBIndex index(DOMString name);
[NewObject] IDBIndex createIndex(DOMString name,
(DOMString or sequence<DOMString>) keyPath,
optional IDBIndexParameters options);
void deleteIndex(DOMString name);
};
dictionary IDBIndexParameters {
boolean unique = false;
boolean multiEntry = false;
};
</xmp>
<div class=note>
<dl class=domintro>
<dt><var>store</var> . {{IDBObjectStore/name}}</dt>
<dd>
Returns the [=object-store/name=] of the store.
</dd>
<dt><var>store</var> . {{IDBObjectStore/name}} = <var>newName</var></dt>
<dd>
Updates the [=object-store/name=] of the store to |newName|.
Throws "{{InvalidStateError}}" {{DOMException}} if not called within an [=/upgrade
transaction=].
</dd>
<dt><var>store</var> . {{IDBObjectStore/keyPath}}</dt>
<dd>
Returns the [=object-store/key path=] of the store, or null if none.
</dd>
<dt><var>list</var> . {{IDBObjectStore/indexNames}}</dt>
<dd>
Returns a list of the names of indexes in the store.
</dd>
<dt><var>store</var> . {{IDBObjectStore/transaction}}</dt>
<dd>
Returns the associated [=/transaction=].
</dd>
<dt><var>store</var> . {{IDBObjectStore/autoIncrement}}</dt>
<dd>
Returns true if the store has a [=key generator=], and false otherwise.
</dd>
</dl>
</div>
The <dfn attribute for=IDBObjectStore>name</dfn> attribute's getter
must return this [=/object store handle=]'s
[=object-store/name=].
<details class=note>
<summary>
Is this the same as the [=/object store=]'s [=object-store/name=]?
</summary>
As long as the [=/transaction=] has not [=transaction/finished=],
this is the same as the associated [=/object store=]'s
[=object-store/name=]. But once the [=/transaction=] has
[=transaction/finished=], this attribute will not reflect changes made with a
later [=/upgrade transaction=].
</details>
<div class=algorithm>
The {{IDBObjectStore/name}} attribute's setter must run these steps:
1. Let |name| be the given value.
1. Let |transaction| be this [=/object store handle=]'s
[=object-store-handle/transaction=].
1. Let |store| be this [=/object store handle=]'s
[=object-store-handle/object store=].
1. If |store| has been deleted,
[=throw=] an "{{InvalidStateError}}" {{DOMException}}.
1. If |transaction| is not an [=/upgrade transaction=],
[=throw=] an "{{InvalidStateError}}" {{DOMException}}.
1. If |transaction| is not [=transaction/active=],
[=throw=] a "{{TransactionInactiveError}}" {{DOMException}}.
1. If |store|'s [=object-store/name=] is equal to |name|,
terminate these steps.
1. If an [=/object store=] [=object-store/named=]
|name| already exists in |store|'s [=database=], [=throw=] a
"{{ConstraintError}}" {{DOMException}}.
1. Set |store|'s [=object-store/name=] to |name|.
1. Set this [=/object store handle=]'s
[=object-store-handle/name=] to |name|.
</div>
The <dfn attribute for=IDBObjectStore>keyPath</dfn> attribute's getter
must return this [=/object store handle=]'s
[=object-store-handle/object store=]'s [=object-store/key path=], or
null if none. The [=/key path=] is converted as a {{DOMString}} (if a
string) or a [=sequence&lt;DOMString&gt;=] (if a list of strings), per
[[!WEBIDL]].
The returned value is not the same instance that was used when the
[=/object store=] was created. However, if this attribute returns
an object (specifically an [=Array=]), it returns the same object
instance every time it is inspected. Changing the properties of the
object has no effect on the [=/object store=].
The <dfn attribute for=IDBObjectStore>indexNames</dfn> attribute's
getter must return a {{DOMStringList}} associated with a [=sorted name list=] of the [=index/names=]
of [=/indexes=] in this [=/object store handle=]'s
[=index set=].
<details class=note>
<summary>
Is this the same as [=/object store=]'s list
of [=/index=] [=index/names=]?
</summary>
As long as the [=/transaction=] has not [=transaction/finished=],
this is the same as the associated [=/object store=]'s list
of [=/index=] [=index/names=]. But once the
[=/transaction=] has [=transaction/finished=], this attribute will not
reflect changes made with a later [=/upgrade transaction=].
</details>
The <dfn attribute for=IDBObjectStore>transaction</dfn> attribute's
getter must return this [=/object store handle=]'s
[=object-store-handle/transaction=].
The <dfn attribute for=IDBObjectStore>autoIncrement</dfn> attribute's
getter must return true if this [=/object store handle=]'s
[=object-store-handle/object store=] has a [=key generator=],
and false otherwise.
<div class=note>
The following methods throw a "{{ReadOnlyError}}" {{DOMException}} if called within a
[=read-only transaction=], and a "{{TransactionInactiveError}}" {{DOMException}} if
called when the [=/transaction=] is not [=transaction/active=].
<dl class=domintro>
<dt>
<var>request</var> = <var>store</var>
. {{IDBObjectStore/put()|put}}(<var>value</var> [, <var>key</var>])
</dt>
<dt>
<var>request</var> = <var>store</var>
. {{IDBObjectStore/add()|add}}(<var>value</var> [, <var>key</var>])
</dt>
<dd>
Adds or updates a [=object-store/record=] in |store| with the given |value|
and |key|.
If the store uses [=in-line keys=] and |key| is specified a
"{{DataError}}" {{DOMException}} will be thrown.
If {{IDBObjectStore/put()}} is used, any existing [=object-store/record=]
with the [=/key=] will be replaced. If {{IDBObjectStore/add()}}
is used, and if a [=object-store/record=] with the [=/key=] already exists
the |request| will fail, with |request|'s {{IDBRequest/error}}
set to a "{{ConstraintError}}" {{DOMException}}.
If successful, |request|'s {{IDBRequest/result}} will be the
[=object-store/record=]'s [=/key=].
</dd>
<dt>
<var>request</var> = <var>store</var> .
{{IDBObjectStore/delete()|delete}}(<var>query</var>)
</dt>
<dd>
Deletes [=object-store/records=] in |store| with the given
[=/key=] or in the given [=key range=] in |query|.
If successful, |request|'s {{IDBRequest/result}} will
be `undefined`.
</dd>
<dt>
<var>request</var> = <var>store</var> . {{IDBObjectStore/clear()|clear}}()
</dt>
<dd>
Deletes all [=object-store/records=] in |store|.
If successful, |request|'s {{IDBRequest/result}} will
be `undefined`.
</dd>
</dl>
</div>
<div class=algorithm>
The <dfn method for=IDBObjectStore>put(|value|, |key|)</dfn> method,
when invoked, must run these steps:
1. Let |transaction| be this [=/object store handle=]'s
[=object-store-handle/transaction=].
1. Let |store| be this [=/object store handle=]'s
[=object-store-handle/object store=].
1. If |store| has been deleted,
[=throw=] an "{{InvalidStateError}}" {{DOMException}}.
1. If |transaction| is not [=transaction/active=],
[=throw=] a "{{TransactionInactiveError}}" {{DOMException}}.
1. If |transaction| is a [=read-only transaction=],
[=throw=] a "{{ReadOnlyError}}" {{DOMException}}.
1. If |store| uses [=in-line keys=] and |key| was given,
[=throw=] a "{{DataError}}" {{DOMException}}.
1. If |store| uses [=out-of-line keys=] and has no [=key
generator=] and |key| was not given, [=throw=] a
"{{DataError}}" {{DOMException}}.
1. If |key| was given, then:
1. Let |r| be the result of running the steps to [=convert a
value to a key=] with |key|. Rethrow any exceptions.
1. If |r| is invalid, [=throw=] a "{{DataError}}" {{DOMException}}.
1. Let |key| be |r|.
1. Let |targetRealm| be a user-agent defined [=Realm=].
1. Let |clone| be a [=clone=] of |value| in |targetRealm|.
Rethrow any exceptions.
<details class=note>
<summary>Why create a copy of the value?</summary>
The value is be serialized when stored. Treating it as a copy
here allows other algorithms in this specification to treat it as
an ECMAScript value, but implementations can optimize this
if the difference in behavior is not observable.
</details>
1. If |store| uses [=in-line keys=], then:
1. Let |kpk| be the result of running the steps to [=extract a
key from a value using a key path=] with |clone| and
|store|'s [=object-store/key path=]. Rethrow any
exceptions.
1. If |kpk| is invalid, [=throw=] a "{{DataError}}" {{DOMException}}.
1. If |kpk| is not failure, let |key| be |kpk|.
1. Otherwise (|kpk| is failure):
1. If |store| does not have a [=key generator=], [=throw=]
a "{{DataError}}" {{DOMException}}.
1. Otherwise, if the steps to
[=check that a key could be injected into a value=] with
|clone| and |store|'s [=object-store/key path=] return
false, [=throw=] a "{{DataError}}" {{DOMException}}.
1. Run the steps to [=asynchronously execute a request=] and
return the {{IDBRequest}} created by these steps. The steps are
run with this [=/object store handle=] as |source| and the
steps to [=store a record into an object store=] as
|operation|, using |store|, the |clone| as |value|, |key|, and
with the |no-overwrite flag| unset.
</div>
<div class=algorithm>
The <dfn method for=IDBObjectStore>add(|value|, |key|)</dfn> method,
when invoked, must run these steps:
1. Let |transaction| be this [=/object store handle=]'s
[=object-store-handle/transaction=].
1. Let |store| be this [=/object store handle=]'s
[=object-store-handle/object store=].
1. If |store| has been deleted, [=throw=] an
"{{InvalidStateError}}" {{DOMException}}.
1. If |transaction| is not [=transaction/active=], [=throw=] a
"{{TransactionInactiveError}}" {{DOMException}}.
1. If |transaction| is a [=read-only transaction=],
[=throw=] a "{{ReadOnlyError}}" {{DOMException}}.
1. If |store| uses [=in-line keys=] and |key| was given,
[=throw=] a "{{DataError}}" {{DOMException}}.
1. If |store| uses [=out-of-line keys=] and has no [=key
generator=] and |key| was not given, [=throw=] a
"{{DataError}}" {{DOMException}}.
1. If |key| was given, then:
1. Let |r| be the result of running the steps to [=convert a
value to a key=] with |key|. Rethrow any exceptions.
1. If |r| is invalid, [=throw=] a "{{DataError}}" {{DOMException}}.
1. Let |key| be |r|.
1. Let |targetRealm| be a user-agent defined [=Realm=].
1. Let |clone| be a [=clone=] of |value| in |targetRealm|.
Rethrow any exceptions.
<details class=note>
<summary>Why create a copy of the value?</summary>
The value is serialized when stored. Treating it as a copy
here allows other algorithms in this specification to treat it as
an ECMAScript value, but implementations can optimize this
if the difference in behavior is not observable.
</details>
1. If |store| uses [=in-line keys=], then:
1. Let |kpk| be the result of running the steps to [=extract a
key from a value using a key path=] with |clone| and
|store|'s [=object-store/key path=]. Rethrow any
exceptions.
1. If |kpk| is invalid, [=throw=] a "{{DataError}}" {{DOMException}}.
1. If |kpk| is not failure, let |key| be
|kpk|.
1. Otherwise (|kpk| is failure):
1. If |store| does not have a [=key generator=], [=throw=]
a "{{DataError}}" {{DOMException}}.
1. Otherwise, if the steps to
[=check that a key could be injected into a value=] with
|clone| and |store|'s [=object-store/key path=] return
false, [=throw=] a "{{DataError}}" {{DOMException}}.
1. Run the steps to [=asynchronously execute a request=] and
return the {{IDBRequest}} created by these steps. The steps are
run with this [=/object store handle=] as |source| and the
steps to [=store a record into an object store=] as
|operation|, using |store|, |clone| as |value|, |key|, and with
the |no-overwrite flag| set.
</div>
<div class=algorithm>
The <dfn method for=IDBObjectStore>delete(|query|)</dfn> method, when
invoked, must run these steps:
1. Let |transaction| be this [=/object store handle=]'s
[=object-store-handle/transaction=].
1. Let |store| be this [=/object store handle=]'s
[=object-store-handle/object store=].
1. If |store| has been deleted, [=throw=] an
"{{InvalidStateError}}" {{DOMException}}.
1. If |transaction| is not [=transaction/active=], [=throw=] a
"{{TransactionInactiveError}}" {{DOMException}}.
1. If |transaction| is a [=read-only transaction=],
[=throw=] a "{{ReadOnlyError}}" {{DOMException}}.
1. Let |range| be the result of running the steps to
[=convert a value to a key range=] with |query| and
|null disallowed flag| set. Rethrow any exceptions.
1. Run the steps to [=asynchronously execute a request=] and
return the {{IDBRequest}} created by these steps. The steps are
run with this [=/object store handle=] as |source| and
the steps to [=delete records from an object store=] as
|operation|, using |store| and |range|.
</div>
The |query| parameter may be a [=/key=] or an
{{IDBKeyRange}} identifying the [=object-store/records=] keys to be
deleted.
<aside class=note>
Unlike other methods which take keys or key ranges, this method does
<strong>not</strong> allow null to be given as key. This is to
reduce the risk that a small bug would clear a whole object store.
</aside>
<div class=algorithm>
The <dfn method for=IDBObjectStore>clear()</dfn> method, when invoked,
must run these steps:
1. Let |transaction| be this [=/object store handle=]'s
[=object-store-handle/transaction=].
1. Let |store| be this [=/object store handle=]'s
[=object-store-handle/object store=].
1. If |store| has been deleted, [=throw=] an
"{{InvalidStateError}}" {{DOMException}}.
1. If |transaction| is not [=transaction/active=], [=throw=] a
"{{TransactionInactiveError}}" {{DOMException}}.
1. If |transaction| is a [=read-only transaction=],
[=throw=] a "{{ReadOnlyError}}" {{DOMException}}.
1. Run the steps to [=asynchronously execute a request=] and
return the {{IDBRequest}} created by these steps. The steps are
run with this [=/object store handle=] as |source| and
the steps to [=clear an object store=] as
|operation|, using |store|.
<div class=note>
The following methods throw a "{{TransactionInactiveError}}" {{DOMException}} if called
when the [=/transaction=] is not [=transaction/active=].
<dl class=domintro>
<dt>
<var>request</var> = <var>store</var> .
{{IDBObjectStore/get()|get}}(<var>query</var>)
</dt>
<dd>
Retrieves the [=/value=] of the first [=object-store/record=] matching the
given [=/key=] or [=key range=] in |query|.
If successful, |request|'s {{IDBRequest/result}} will be the
[=/value=], or `undefined` if there was no matching
[=object-store/record=].
</dd>
<dt>
<var>request</var> = <var>store</var> .
{{IDBObjectStore/getKey()|getKey}}(<var>query</var>)
</dt>
<dd>
Retrieves the [=/key=] of the first [=object-store/record=] matching the
given [=/key=] or [=key range=] in |query|.
If successful, |request|'s {{IDBRequest/result}} will be the
[=/key=], or `undefined` if there was no matching
[=object-store/record=].
</dd>
<dt>
<var>request</var> = <var>store</var> .
{{IDBObjectStore/getAll()|getAll}}(<var>query</var> [, <var>count</var>])
</dt>
<dd>
Retrieves the [=/values=] of the [=object-store/records=] matching the
given [=/key=] or [=key range=] in |query| (up to |count| if given).
If successful, |request|'s {{IDBRequest/result}} will
be an [=Array=] of the [=/values=].
</dd>
<dt>
<var>request</var> = <var>store</var> .
{{IDBObjectStore/getAllKeys()|getAllKeys}}(<var>query</var> [,
<var>count</var>])
</dt>
<dd>
Retrieves the [=/keys=] of [=object-store/records=] matching the
given [=/key=] or [=key range=] in |query| (up to |count| if given).
If successful, |request|'s {{IDBRequest/result}} will
be an [=Array=] of the [=/keys=].
</dd>
<dt>
<var>request</var> = <var>store</var> .
{{IDBObjectStore/count()|count}}(<var>query</var>)
</dt>
<dd>
Retrieves the number of [=object-store/records=] matching the
given [=/key=] or [=key range=] in |query|.
If successful, |request|'s {{IDBRequest/result}} will be the count.
</dd>
</dl>
</div>
The <dfn method for=IDBObjectStore>get(|query|)</dfn> method, when
invoked, must run these steps:
1. Let |transaction| be this [=/object store handle=]'s
[=object-store-handle/transaction=].
1. Let |store| be this [=/object store handle=]'s
[=object-store-handle/object store=].
1. If |store| has been deleted, [=throw=] an
"{{InvalidStateError}}" {{DOMException}}.
1. If |transaction| is not [=transaction/active=], [=throw=] a
"{{TransactionInactiveError}}" {{DOMException}}.
1. Let |range| be the result of running the steps to
[=convert a value to a key range=] with |query| and
|null disallowed flag| set. Rethrow any exceptions.
1. Run the steps to [=asynchronously execute a request=] and
return the {{IDBRequest}} created by these steps. The steps
are run with this [=/object store handle=] as
|source| and the steps to [=retrieve a value from
an object store=] as |operation|, using the
[=current Realm=] as |targetRealm|,
|store| and |range|.
</div>
The |query| parameter may be a [=/key=] or an
{{IDBKeyRange}} identifying the [=object-store/record=] to be retrieved. If a
range is specified, the method retrieves the first existing value in
that range.
<aside class=note>
This method produces the same result if a record with the given key
doesn't exist as when a record exists, but has `undefined` as value.
If you need to tell the two situations apart, you can use
{{IDBObjectStore/openCursor()}} with the same key. This will return
a cursor with `undefined` as value if a record exists, or no cursor if
no such record exists.
</aside>
<div class=algorithm>
The <dfn method for=IDBObjectStore>getKey(|query|)</dfn> method, when
invoked, must run these steps:
1. Let |transaction| be this [=/object store handle=]'s
[=object-store-handle/transaction=].
1. Let |store| be this [=/object store handle=]'s
[=object-store-handle/object store=].
1. If |store| has been deleted, [=throw=] an
"{{InvalidStateError}}" {{DOMException}}.
1. If |transaction| is not [=transaction/active=], [=throw=] a
"{{TransactionInactiveError}}" {{DOMException}}.
1. Let |range| be the result of running the steps to
[=convert a value to a key range=] with |query| and
|null disallowed flag| set. Rethrow any exceptions.
1. Run the steps to [=asynchronously execute a request=] and
return the {{IDBRequest}} created by these steps. The steps
are run with this [=/object store handle=] as
|source| and the steps to [=retrieve a key from an
object store=] as |operation|, using |store|
and |range|.
</div>
The |query| parameter may be a [=/key=] or an
{{IDBKeyRange}} identifying the [=object-store/record=] key to be
retrieved. If a range is specified, the method retrieves
the first existing key in that range.
<div class=algorithm>
The <dfn method for=IDBObjectStore>getAll(|query|, |count|)</dfn>
method, when invoked, must run these steps:
1. Let |transaction| be this [=/object store handle=]'s
[=object-store-handle/transaction=].
1. Let |store| be this [=/object store handle=]'s
[=object-store-handle/object store=].
1. If |store| has been deleted, [=throw=] an
"{{InvalidStateError}}" {{DOMException}}.
1. If |transaction| is not [=transaction/active=], [=throw=] a
"{{TransactionInactiveError}}" {{DOMException}}.
1. Let |range| be the result of running the steps to
[=convert a value to a key range=] with |query|.
Rethrow any exceptions.
1. Run the steps to [=asynchronously execute a request=] and
return the {{IDBRequest}} created by these steps. The steps are
run with this [=/object store handle=] as |source| and the
steps to [=retrieve multiple values from an object store=]
as |operation|, using the [=current Realm=] as |targetRealm|,
|store|, |range|, and |count| if given.
</div>
The |query| parameter may be a [=/key=] or an {{IDBKeyRange}}
identifying the [=object-store/records=] to be retrieved. If null or not given,
an [=unbounded key range=] is used. If |count| is specified and
there are more than |count| records in range, only the first |count|
will be retrieved.
<div class=algorithm>
The <dfn method for=IDBObjectStore>getAllKeys(|query|, |count|)</dfn>
method, when invoked, must run these steps:
1. Let |transaction| be this [=/object store handle=]'s
[=object-store-handle/transaction=].
1. Let |store| be this [=/object store handle=]'s
[=object-store-handle/object store=].
1. If |store| has been deleted, [=throw=] an
"{{InvalidStateError}}" {{DOMException}}.
1. If |transaction| is not [=transaction/active=], [=throw=] a
"{{TransactionInactiveError}}" {{DOMException}}.
1. Let |range| be the result of running the steps to
[=convert a value to a key range=] with |query|.
Rethrow any exceptions.
1. Run the steps to [=asynchronously execute a request=] and
return the {{IDBRequest}} created by these steps. The steps are
run with this [=/object store handle=] as |source| and the
steps to [=retrieve multiple keys from an object store=] as
|operation|, using |store|, |range|, and |count| if given.
</div>
The |query| parameter may be a [=/key=] or an {{IDBKeyRange}}
identifying the [=object-store/records=] keys to be retrieved. If null or not
given, an [=unbounded key range=] is used. If |count| is specified
and there are more than |count| keys in range, only the first |count|
will be retrieved.
<div class=algorithm>
The <dfn method for=IDBObjectStore>count(|query|)</dfn> method, when
invoked, must run these steps:
1. Let |transaction| be this [=/object store handle=]'s
[=object-store-handle/transaction=].
1. Let |store| be this [=/object store handle=]'s
[=object-store-handle/object store=].
1. If |store| has been deleted, [=throw=] an
"{{InvalidStateError}}" {{DOMException}}.
1. If |transaction| is not [=transaction/active=], [=throw=] a
"{{TransactionInactiveError}}" {{DOMException}}.
1. Let |range| be the result of running the steps to
[=convert a value to a key range=] with |query|.
Rethrow any exceptions.
1. Run the steps to [=asynchronously execute a request=] and
return the {{IDBRequest}} created by these steps. The steps are
run with this [=/object store handle=] as |source| and the
steps to [=count the records in a range=] as |operation|, with
|source| and |range|.
</div>
The |query| parameter may be a [=/key=] or an {{IDBKeyRange}}
identifying the [=object-store/records=] keys to be counted. If null or not
given, an [=unbounded key range=] is used.
<div class=note>
The following methods throw a "{{TransactionInactiveError}}" {{DOMException}} if called
when the [=/transaction=] is not [=transaction/active=].
<dl class=domintro>
<dt>
<var>request</var> = <var>store</var> .
{{IDBObjectStore/openCursor()|openCursor}}([<var>query</var>
[, <var>direction</var> = "next"]])
</dt>
<dd>
Opens a [=cursor=] over the [=object-store/records=] matching |query|,
ordered by |direction|. If |query| is null, all [=object-store/records=] in
|store| are matched.
If successful, |request|'s {{IDBRequest/result}} will be an
{{IDBCursorWithValue}} pointing at the first matching
[=object-store/record=], or null if there were no matching [=object-store/records=].
</dd>
<dt>
<var>request</var> = <var>store</var> .
{{IDBObjectStore/openKeyCursor()|openKeyCursor}}([<var>query</var>
[, <var>direction</var> = "next"]])
</dt>
<dd>
Opens a [=cursor=] with [=cursor/key only flag=] set over the
[=object-store/records=] matching |query|, ordered by |direction|. If
|query| is null, all [=object-store/records=] in |store| are matched.
If successful, |request|'s {{IDBRequest/result}} will be an
{{IDBCursor}} pointing at the first matching [=object-store/record=], or
null if there were no matching [=object-store/records=].
</dd>
</dl>
</div>
<div class=algorithm>
The <dfn method for=IDBObjectStore>openCursor(|query|,
|direction|)</dfn> method, when invoked, must run these steps:
1. Let |transaction| be this [=/object store handle=]'s
[=object-store-handle/transaction=].
1. Let |store| be this [=/object store handle=]'s
[=object-store-handle/object store=].
1. If |store| has been deleted, [=throw=] an
"{{InvalidStateError}}" {{DOMException}}.
1. If |transaction| is not [=transaction/active=], [=throw=] a
"{{TransactionInactiveError}}" {{DOMException}}.
1. Let |range| be the result of running the steps to
[=convert a value to a key range=] with |query|.
Rethrow any exceptions.
1. Let |cursor| be a new [=cursor=] with
[=cursor/transaction=] set to |transaction|, an undefined
[=cursor/position=], [=cursor/direction=] set to |direction|, [=got value
flag=] unset, and undefined [=cursor/key=] and
[=cursor/value=]. The [=cursor/source=] of |cursor| is
|store|. The [=cursor/range=] of |cursor| is |range|.
1. Run the steps to [=asynchronously execute a request=] and
return the {{IDBRequest}} created by these steps. The steps are
run with this [=/object store handle=] as |source| and the
steps to [=iterate a cursor=] as |operation|, using
the [=current Realm=] as |targetRealm|, and |cursor|.
</div>
The |query| parameter may be a [=/key=] or an
{{IDBKeyRange}} to use as the [=cursor=]'s [=cursor/range=].
If null or not given, an [=unbounded key range=] is used.
<div class=algorithm>
The <dfn method for=IDBObjectStore>openKeyCursor(|query|,
|direction|)</dfn> method, when invoked, must run these steps:
1. Let |transaction| be this [=/object store handle=]'s
[=object-store-handle/transaction=].
1. Let |store| be this [=/object store handle=]'s
[=object-store-handle/object store=].
1. If |store| has been deleted, [=throw=] an
"{{InvalidStateError}}" {{DOMException}}.
1. If |transaction| is not [=transaction/active=], [=throw=] a
"{{TransactionInactiveError}}" {{DOMException}}.
1. Let |range| be the result of running the steps to
[=convert a value to a key range=] with |query|.
Rethrow any exceptions.
1. Let |cursor| be a new [=cursor=] with
[=cursor/transaction=] set to
|transaction|, an undefined [=cursor/position=],
[=cursor/direction=] set to |direction|, [=got value
flag=] unset, and undefined [=cursor/key=] and
[=cursor/value=]. The
[=cursor/source=] of |cursor| is
|store|. The [=cursor/range=] of |cursor| is
|range|. The [=key only flag=] of |cursor| is
set.
1. Run the steps to [=asynchronously execute a request=] and
return the {{IDBRequest}} created by these steps. The steps are
run with this [=/object store handle=] as |source| and
the steps to [=iterate a cursor=] as |operation|,
using the [=current Realm=] as |targetRealm|, and |cursor|.
</div>
The |query| parameter may be a [=/key=] or an
{{IDBKeyRange}} to use as the [=cursor=]'s [=cursor/range=]. If null
or not given, an [=unbounded key range=] is used.
<div class=note>
<dl class=domintro>
<dt>
<var>index</var> = <var>store</var> . index(<var>name</var>)
</dt>
<dd>
Returns an {{IDBIndex}} for the [=/index=] named |name| in |store|.
</dd>
<dt>
<var>index</var> = <var>store</var> .
{{IDBObjectStore/createIndex()|createIndex}}(<var>name</var>,
<var>keyPath</var> [, <var>options</var>])
</dt>
<dd>
Creates a new [=/index=] in |store| with the given |name|,
|keyPath| and |options| and returns a new {{IDBIndex}}. If the
|keyPath| and |options| define constraints that cannot be
satisfied with the data already in |store| the [=/upgrade
transaction=] will [=transaction/abort=] with
a "{{ConstraintError}}" {{DOMException}}.
Throws an "{{InvalidStateError}}" {{DOMException}} if not called within an [=/upgrade
transaction=].
</dd>
<dt>
<var>store</var> . {{IDBObjectStore/deleteIndex()|deleteIndex}}(<var>name</var>)
</dt>
<dd>
Deletes the [=/index=] in |store| with the given |name|.
Throws an "{{InvalidStateError}}" {{DOMException}} if not called within an [=/upgrade
transaction=].
</dd>
</dl>
</div>
<div class=algorithm>
The <dfn method for=IDBObjectStore>createIndex(|name|, |keyPath|,
|options|)</dfn> method, when invoked, must run these steps:
1. Let |transaction| be this [=/object store handle=]'s
[=object-store-handle/transaction=].
1. Let |store| be this [=/object store handle=]'s
[=object-store-handle/object store=].
1. If |transaction| is not an [=/upgrade transaction=],
[=throw=] an "{{InvalidStateError}}" {{DOMException}}.
1. If |store| has been deleted, [=throw=] an
"{{InvalidStateError}}" {{DOMException}}.
1. If |transaction| is not [=transaction/active=], [=throw=] a
"{{TransactionInactiveError}}" {{DOMException}}.
1. If an [=/index=] [=index/named=]
|name| already exists in |store|, [=throw=] a
"{{ConstraintError}}" {{DOMException}}.
1. If |keyPath| is not a [=valid key path=], [=throw=]
a "{{SyntaxError}}" {{DOMException}}.
1. Let |unique| be set if |options|'s
{{IDBIndexParameters/unique}} member is true, and unset otherwise.
1. Let |multiEntry| be set if |options|'s
{{IDBIndexParameters/multiEntry}} member is true, and unset otherwise.
1. If |keyPath| is a sequence and |multiEntry| is
set, [=throw=] an "{{InvalidAccessError}}" {{DOMException}}.
1. Let |index| be a new [=/index=] in |store|.
Set |index|'s [=index/name=] to
|name| and [=index/key path=] to
|keyPath|. If |unique| is set, set
|index|'s [=unique flag=]. If |multiEntry| is
set, set |index|'s [=multiEntry flag=].
1. Add |index| to this [=/object store handle=]'s [=index
set=].
1. Return a new [=index handle=] associated with |index|
and this [=/object store handle=].
</div>
This method creates and returns a new [=/index=] with the
given name in the [=/object store=]. Note that this method
must only be called from within an [=/upgrade transaction=].
The index that is requested to be created can contain constraints on
the data allowed in the index's [=referenced=] object store, such
as requiring uniqueness of the values referenced by the index's
[=index/key path=]. If the [=referenced=] object store already contains data
which violates these constraints, this must not cause the
implementation of {{IDBObjectStore/createIndex()}} to throw an
exception or affect what it returns. The implementation must still
create and return an {{IDBIndex}} object, and the implementation must
[=queue a task=] to abort the [=/upgrade transaction=] which was
used for the {{IDBObjectStore/createIndex()}} call.
This method synchronously modifies the {{IDBObjectStore/indexNames}}
property on the {{IDBObjectStore}} instance on which it was called.
Although this method does not return an {{IDBRequest}} object, the
index creation itself is processed as an asynchronous request within
the [=/upgrade transaction=].
In some implementations it is possible for the implementation to
asynchronously run into problems creating the index after the
createIndex method has returned. For example in implementations where
metadata about the newly created index is queued up to be inserted
into the database asynchronously, or where the implementation might
need to ask the user for permission for quota reasons. Such
implementations must still create and return an {{IDBIndex}} object,
and once the implementation determines that creating the index has
failed, it must abort the transaction using the steps to [=abort
a transaction=] using an appropriate error as |error|. For example
if creating the [=/index=] failed due to quota reasons,
a "{{QuotaExceededError}}" {{DOMException}} must be used as error and if the index can't be
created due to [=unique flag=] constraints, a "{{ConstraintError}}" {{DOMException}}
must be used as error.
<aside class=example id=example-async-index-creation>
The asynchronous creation of indexes is observable in the following example:
```js
var request1 = objectStore.put({name: "betty"}, 1);
var request2 = objectStore.put({name: "betty"}, 2);
var index = objectStore.createIndex("by_name", "name", {unique: true});
```
At the point where {{createIndex()}} called, neither of the
[=requests=] have executed. When the second request executes, a
duplicate name is created. Since the index creation is considered an
asynchronous [=request=], the index's <a data-lt="unique
flag">uniqueness constraint</a> does not cause the second
[=request=] to fail. Instead, the [=/transaction=] will
be [=transaction/aborted=] when the index is created and the constraint
fails.
</aside>
<div class=algorithm>
The <dfn method for=IDBObjectStore>index(|name|)</dfn> method, when
invoked, must run these steps:
1. Let |transaction| be this [=/object store handle=]'s
[=object-store-handle/transaction=].
1. Let |store| be this [=/object store handle=]'s
[=object-store-handle/object store=].
1. If |store| has been deleted, [=throw=] an
"{{InvalidStateError}}" {{DOMException}}.
1. If |transaction| has [=transaction/finished=], [=throw=] an
"{{InvalidStateError}}" {{DOMException}}.
1. Let |index| be the [=/index=]
[=index/named=] |name| in this [=/object
store handle=]'s [=index set=] if one exists, or [=throw=]
a "{{NotFoundError}}" {{DOMException}} otherwise.
1. Return an [=index handle=] associated with |index| and
this [=/object store handle=].
</div>
<aside class=note>
Each call to this method on the same {{IDBObjectStore}} instance
with the same name returns the same {{IDBIndex}} instance.
</aside>
<aside class=note>
The returned {{IDBIndex}} instance is specific to this
{{IDBObjectStore}} instance. If this method is called on a
different {{IDBObjectStore}} instance with the same name, a
different {{IDBIndex}} instance is returned.
</aside>
<div class=algorithm>
The <dfn method for=IDBObjectStore>deleteIndex(|name|)</dfn> method,
when invoked, must run these steps:
1. Let |transaction| be this [=/object store handle=]'s
[=object-store-handle/transaction=].
1. Let |store| be this [=/object store handle=]'s
[=object-store-handle/object store=].
1. If |transaction| is not an [=/upgrade transaction=],
[=throw=] an "{{InvalidStateError}}" {{DOMException}}.
1. If |store| has been deleted, [=throw=] an
"{{InvalidStateError}}" {{DOMException}}.
1. If |transaction| is not [=transaction/active=], [=throw=] a
"{{TransactionInactiveError}}" {{DOMException}}.
1. Let |index| be the [=/index=] [=index/named=] |name|
in |store| if one exists, or [=throw=] a "{{NotFoundError}}" {{DOMException}}
otherwise.
1. Remove |index| from this [=/object store handle=]'s
[=index set=].
1. Destroy |index|.
</div>
This method destroys the [=/index=] with the given name in the
[=/object store=]. Note that this method must only be called from
within an [=/upgrade transaction=].
This method synchronously modifies the {{IDBObjectStore/indexNames}}
property on the {{IDBObjectStore}} instance on which it was called.
Although this method does not return an {{IDBRequest}} object, the
index destruction itself is processed as an asynchronous request
within the [=/upgrade transaction=].
<!-- ============================================================ -->
## The {{IDBIndex}} interface ## {#index-interface}
<!-- ============================================================ -->
The {{IDBIndex}} interface represents an [=index handle=].
<xmp class=idl>
[Exposed=(Window,Worker)]
interface IDBIndex {
attribute DOMString name;
[SameObject] readonly attribute IDBObjectStore objectStore;
readonly attribute any keyPath;
readonly attribute boolean multiEntry;
readonly attribute boolean unique;
[NewObject] IDBRequest get(any query);
[NewObject] IDBRequest getKey(any query);
[NewObject] IDBRequest getAll(optional any query,
optional [EnforceRange] unsigned long count);
[NewObject] IDBRequest getAllKeys(optional any query,
optional [EnforceRange] unsigned long count);
[NewObject] IDBRequest count(optional any query);
[NewObject] IDBRequest openCursor(optional any query,
optional IDBCursorDirection direction = "next");
[NewObject] IDBRequest openKeyCursor(optional any query,
optional IDBCursorDirection direction = "next");
};
</xmp>
<div class=note>
<dl class=domintro>
<dt><var>index</var> . {{IDBIndex/name}}</dt>
<dd>
Returns the [=index/name=] of the index.
</dd>
<dt><var>index</var> . {{IDBIndex/name}} = <var>newName</var></dt>
<dd>
Updates the [=index/name=] of the store to |newName|.
Throws an "{{InvalidStateError}}" {{DOMException}} if not called within an [=/upgrade
transaction=].
</dd>
<dt><var>index</var> . {{IDBIndex/objectStore}}</dt>
<dd>
Returns the {{IDBObjectStore}} the index belongs to.
</dd>
<dt><var>index</var> . keyPath</dt>
<dd>
Returns the [=/key path=] of the index.
</dd>
<dt><var>index</var> . multiEntry</dt>
<dd>
Returns true if the index's [=index/multiEntry flag=] is set.
</dd>
<dt><var>index</var> . unique</dt>
<dd>
Returns true if the index's [=index/unique flag=] is set.
</dd>
</dl>
</div>
The <dfn attribute for=IDBIndex>name</dfn> attribute's getter must
return this [=index handle=]'s [=index/name=].
<details class=note>
<summary>
Is this the same as the [=/index=]'s [=index/name=]?
</summary>
As long as the [=/transaction=] has not [=transaction/finished=],
this is the same as the associated [=/index=]'s
[=index/name=]. But once the [=/transaction=] has
[=transaction/finished=], this attribute will not reflect changes made with a
later [=/upgrade transaction=].
</details>
<div class=algorithm>
The {{IDBIndex/name}} attribute's setter must run these steps:
1. Let |name| be the given value.
1. Let |transaction| be this [=index handle=]'s
[=index-handle/transaction=].
1. Let |index| be this [=index handle=]'s
[=index-handle/index=].
1. If |transaction| is not an [=/upgrade transaction=],
[=throw=] an "{{InvalidStateError}}" {{DOMException}}.
1. If |transaction| is not [=transaction/active=], [=throw=] a
"{{TransactionInactiveError}}" {{DOMException}}.
1. If |index| or |index|'s [=/object store=] has
been deleted, [=throw=] an "{{InvalidStateError}}" {{DOMException}}.
1. If |index|'s [=index/name=] is equal to
|name|, terminate these steps.
1. If an [=/index=] [=index/named=]
|name| already exists in |index|'s [=/object
store=], [=throw=] a "{{ConstraintError}}" {{DOMException}}.
1. Set |index|'s [=index/name=] to
|name|.
1. Set this [=index handle=]'s
[=index-handle/name=] to |name|.
</div>
The <dfn attribute for=IDBIndex>objectStore</dfn> attribute's getter
must return this [=index handle=]'s [=index-handle/object
store handle=].
The <dfn attribute for=IDBIndex>keyPath</dfn> attribute's getter must
return this [=index handle=]'s [=index-handle/index=]'s
[=object-store/key path=]. The [=/key path=] is converted as a
{{DOMString}} (if a string) or a [=sequence&lt;DOMString&gt;=] (if a
list of strings), per [[!WEBIDL]].
The returned value is not the same instance that was used when the
[=/index=] was created. However, if this attribute returns an
object (specifically an [=Array=]), it returns the same object
instance every time it is inspected. Changing the properties of the
object has no effect on the [=/index=].
The <dfn attribute for=IDBIndex>multiEntry</dfn> attribute's getter
must return true if this [=index handle=]'s
[=index-handle/index=]'s [=multiEntry flag=] is set, and false
otherwise.
The <dfn attribute for=IDBIndex>unique</dfn> attribute's getter must
return true if this [=index handle=]'s
[=index-handle/index=]'s [=unique flag=] is set, and false
otherwise.
<div class=note>
The following methods throw an "{{TransactionInactiveError}}" {{DOMException}} if called
when the [=/transaction=] is not [=transaction/active=].
<dl class=domintro>
<dt>
<var>request</var> = <var>store</var> .
{{IDBIndex/get()|get}}(<var>query</var>)
</dt>
<dd>
Retrieves the [=/value=] of the first [=object-store/record=] matching the
given [=/key=] or [=key range=] in |query|.
If successful, |request|'s {{IDBRequest/result}} will be the
[=/value=], or `undefined` if there was no matching
[=object-store/record=].
</dd>
<dt>
<var>request</var> = <var>store</var> .
{{IDBIndex/getKey()|getKey}}(<var>query</var>)
</dt>
<dd>
Retrieves the [=/key=] of the first [=object-store/record=] matching the
given [=/key=] or [=key range=] in |query|.
If successful, |request|'s {{IDBRequest/result}} will be the
[=/key=], or `undefined` if there was no matching
[=object-store/record=].
</dd>
<dt>
<var>request</var> = <var>store</var> .
{{IDBIndex/getAll()|getAll}}(<var>query</var> [, <var>count</var>])
</dt>
<dd>
Retrieves the [=/values=] of the [=object-store/records=] matching the given
[=/key=] or [=key range=] in |query| (up to |count| if given).
If successful, |request|'s {{IDBRequest/result}} will be an
[=Array=] of the [=/values=].
</dd>
<dt>
<var>request</var> = <var>store</var> .
{{IDBIndex/getAllKeys()|getAllKeys}}(<var>query</var> [,
<var>count</var>])
</dt>
<dd>
Retrieves the [=/keys=] of [=object-store/records=] matching the given
[=/key=] or [=key range=] in |query| (up to |count| if given).
If successful, |request|'s {{IDBRequest/result}} will be an
[=Array=] of the [=/keys=].
</dd>
<dt>
<var>request</var> = <var>store</var> .
{{IDBIndex/count()|count}}(<var>query</var>)
</dt>
<dd>
Retrieves the number of [=object-store/records=] matching the given [=/key=]
or [=key range=] in |query|.
If successful, |request|'s {{IDBRequest/result}} will be the
count.
</dd>
</dl>
</div>
<div class=algorithm>
The <dfn method for=IDBIndex>get(|query|)</dfn> method, when invoked,
must run these steps:
1. Let |transaction| be this [=index handle=]'s
[=index-handle/transaction=].
1. Let |index| be this [=index handle=]'s
[=index-handle/index=].
1. If |index| or |index|'s [=/object store=] has
been deleted, [=throw=] an "{{InvalidStateError}}" {{DOMException}}.
1. If |transaction| is not [=transaction/active=], [=throw=] a
"{{TransactionInactiveError}}" {{DOMException}}.
1. Let |range| be the result of running the steps to
[=convert a value to a key range=] with |query| and
|null disallowed flag| set. Rethrow any exceptions.
1. Run the steps to [=asynchronously execute a request=] and
return the {{IDBRequest}} created by these steps. The steps
are run with this [=index handle=] as |source| and
the steps to [=retrieve a referenced value from an index=]
as |operation|, using the [=current Realm=] as |targetRealm|,
|index| and |range|.
</div>
The |query| parameter may be a [=/key=] or an
{{IDBKeyRange}} identifying the [=object-store/record=] to be retrieved. If a
range is specified, the method retrieves the first existing record in
that range.
<aside class=note>
This method produces the same result if a record with the given key
doesn't exist as when a record exists, but has `undefined` as value.
If you need to tell the two situations apart, you can use
{{IDBIndex/openCursor()}} with the same key. This will return a
cursor with `undefined` as value if a record exists, or no cursor if
no such record exists.
</aside>
<div class=algorithm>
The <dfn method for=IDBIndex>getKey(|query|)</dfn> method, when
invoked, must run these steps:
1. Let |transaction| be this [=index handle=]'s
[=index-handle/transaction=].
1. Let |index| be this [=index handle=]'s
[=index-handle/index=].
1. If |index| or |index|'s [=/object store=] has been deleted,
[=throw=] an "{{InvalidStateError}}" {{DOMException}}.
1. If |transaction| is not [=transaction/active=], [=throw=] a
"{{TransactionInactiveError}}" {{DOMException}}.
1. Let |range| be the result of running the steps to [=convert a
value to a key range=] with |query| and |null disallowed flag|
set. Rethrow any exceptions.
1. Run the steps to [=asynchronously execute a request=] and
return the {{IDBRequest}} created by these steps. The steps are
run with this [=index handle=] as |source| and the steps to
[=retrieve a value from an index=] as |operation|, using |index|
and |range|.
</div>
The |query| parameter may be a [=/key=] or an
{{IDBKeyRange}} identifying the [=object-store/record=] key to be retrieved.
If a range is specified, the method retrieves the first existing key
in that range.
<div class=algorithm>
The <dfn method for=IDBIndex>getAll(|query|, |count|)</dfn> method,
when invoked, must run these steps:
1. Let |transaction| be this [=index handle=]'s
[=index-handle/transaction=].
1. Let |index| be this [=index handle=]'s
[=index-handle/index=].
1. If |index| or |index|'s [=/object store=] has
been deleted, [=throw=] an "{{InvalidStateError}}" {{DOMException}}.
1. If |transaction| is not [=transaction/active=], [=throw=] a
"{{TransactionInactiveError}}" {{DOMException}}.
1. Let |range| be the result of running the steps to
[=convert a value to a key range=] with |query|.
Rethrow any exceptions.
1. Run the steps to [=asynchronously execute a request=] and
return the {{IDBRequest}} created by these steps. The steps are
run with this [=index handle=] as |source| and the steps to
[=retrieve multiple referenced values from an index=] as
|operation|, using the [=current Realm=] as |targetRealm|,
|index|, |range|, and |count| if given.
</div>
The |query| parameter may be a [=/key=] or an {{IDBKeyRange}}
identifying the [=object-store/records=] to be retrieved. If null or not given,
an [=unbounded key range=] is used. If |count| is specified and
there are more than |count| records in range, only the first |count|
will be retrieved.
<div class=algorithm>
The <dfn method for=IDBIndex>getAllKeys(|query|, |count|)</dfn>
method, when invoked, must run these steps:
1. Let |transaction| be this [=index handle=]'s
[=index-handle/transaction=].
1. Let |index| be this [=index handle=]'s
[=index-handle/index=].
1. If |index| or |index|'s [=/object store=] has
been deleted, [=throw=] an "{{InvalidStateError}}" {{DOMException}}.
1. If |transaction| is not [=transaction/active=], [=throw=] a
"{{TransactionInactiveError}}" {{DOMException}}.
1. Let |range| be the result of running the steps to
[=convert a value to a key range=] with |query|.
Rethrow any exceptions.
1. Run the steps to [=asynchronously execute a request=] and
return the {{IDBRequest}} created by these steps. The steps are
run with this [=index handle=] as |source| and the steps to
[=retrieve multiple values from an index=] as |operation|, using
|index|, |range|, and |count| if given.
</div>
The |query| parameter may be a [=/key=] or an {{IDBKeyRange}}
identifying the [=object-store/records=] keys to be retrieved. If null or not
given, an [=unbounded key range=] is used. If |count| is specified
and there are more than |count| keys in range, only the first |count|
will be retrieved.
<div class=algorithm>
The <dfn method for=IDBIndex>count(|query|)</dfn> method, when
invoked, must run these steps:
1. Let |transaction| be this [=index handle=]'s
[=index-handle/transaction=].
1. Let |index| be this [=index handle=]'s
[=index-handle/index=].
1. If |index| or |index|'s [=/object store=] has
been deleted, [=throw=] an "{{InvalidStateError}}" {{DOMException}}.
1. If |transaction| is not [=transaction/active=], [=throw=] a
"{{TransactionInactiveError}}" {{DOMException}}.
1. Let |range| be the result of running the steps to
[=convert a value to a key range=] with |query|.
Rethrow any exceptions.
1. Run the steps to [=asynchronously execute a request=] and
return the {{IDBRequest}} created by these steps. The steps are
run with this [=index handle=] as |source| and the steps to
[=count the records in a range=] as |operation|, with
[=/index=] as |source| and |range|.
</div>
The |query| parameter may be a [=/key=] or an {{IDBKeyRange}}
identifying the [=object-store/records=] keys to be counted. If null or not
given, an [=unbounded key range=] is used.
<div class=note>
The following methods throw an "{{TransactionInactiveError}}" {{DOMException}} if called
when the [=/transaction=] is not [=transaction/active=].
<dl class=domintro>
<dt>
<var>request</var> = <var>store</var> .
{{IDBIndex/openCursor()|openCursor}}([<var>query</var>
[, <var>direction</var> = "next"]])
</dt>
<dd>
Opens a [=cursor=] over the [=object-store/records=] matching |query|,
ordered by |direction|. If |query| is null, all [=object-store/records=] in
|index| are matched.
If successful, |request|'s {{IDBRequest/result}} will be an
{{IDBCursorWithValue}}, or null if there were no matching
[=object-store/records=].
</dd>
<dt>
<var>request</var> = <var>store</var> .
{{IDBIndex/openKeyCursor()|openKeyCursor}}([<var>query</var>
[, <var>direction</var> = "next"]])
</dt>
<dd>
Opens a [=cursor=] with [=cursor/key only flag=] set over the
[=object-store/records=] matching |query|, ordered by |direction|. If
|query| is null, all [=object-store/records=] in |index| are matched.
If successful, |request|'s {{IDBRequest/result}} will be an
{{IDBCursor}}, or null if there were no matching [=object-store/records=].
</dd>
</dl>
</div>
<div class=algorithm>
The <dfn method for=IDBIndex>openCursor(|query|, |direction|)</dfn>
method, when invoked, must run these steps:
1. Let |transaction| be this [=index handle=]'s
[=index-handle/transaction=].
1. Let |index| be this [=index handle=]'s
[=index-handle/index=].
1. If |index| or |index|'s [=/object store=] has been deleted,
[=throw=] an "{{InvalidStateError}}" {{DOMException}}.
1. If |transaction| is not [=transaction/active=], [=throw=] a
"{{TransactionInactiveError}}" {{DOMException}}.
1. Let |range| be the result of running the steps to
[=convert a value to a key range=] with |query|.
Rethrow any exceptions.
1. Let |cursor| be a new [=cursor=] with
[=cursor/transaction=] set to |transaction|, an undefined
[=cursor/position=], [=cursor/direction=] set to |direction|, [=got value
flag=] unset, and undefined [=cursor/key=] and
[=cursor/value=]. The [=cursor/source=] of |cursor| is
|index|. The [=cursor/range=] of |cursor| is |range|.
1. Run the steps to [=asynchronously execute a request=] and
return the {{IDBRequest}} created by these steps. The steps are
run with this [=index handle=] as |source| and the steps to
[=iterate a cursor=] as |operation|, using the [=current Realm=]
as |targetRealm|, and |cursor|.
</div>
The |query| parameter may be a [=/key=] or an
{{IDBKeyRange}} to use as the [=cursor=]'s [=cursor/range=]. If null
or not given, an [=unbounded key range=] is used.
<div class=algorithm>
The <dfn method for=IDBIndex>openKeyCursor(|query|, |direction|)</dfn>
method, when invoked, must run these steps:
1. Let |transaction| be this [=index handle=]'s
[=index-handle/transaction=].
1. Let |index| be this [=index handle=]'s
[=index-handle/index=].
1. If |index| or |index|'s [=/object store=] has
been deleted, [=throw=] an "{{InvalidStateError}}" {{DOMException}}.
1. If |transaction| is not [=transaction/active=], [=throw=] a
"{{TransactionInactiveError}}" {{DOMException}}.
1. Let |range| be the result of running the steps to
[=convert a value to a key range=] with |query|.
Rethrow any exceptions.
1. Let |cursor| be a new [=cursor=] with
[=cursor/transaction=] set to |transaction|, an undefined
[=cursor/position=], [=cursor/direction=] set to |direction|, [=got value
flag=] unset, and undefined [=cursor/key=] and
[=cursor/value=]. The [=cursor/source=] of |cursor| is
|index|. The [=cursor/range=] of |cursor| is |range|. The [=key only
flag=] of |cursor| is set.
1. Run the steps to [=asynchronously execute a request=] and
return the {{IDBRequest}} created by these steps. The steps are
run with this [=index handle=] as |source| and the
steps to [=iterate a cursor=] as |operation|, using the
[=current Realm=] as |targetRealm|, and |cursor|.
</div>
The |query| parameter may be a [=/key=] or an
{{IDBKeyRange}} to use as the [=cursor=]'s [=cursor/range=]. If null
or not given, an [=unbounded key range=] is used.
<!-- ============================================================ -->
## The {{IDBKeyRange}} interface ## {#keyrange}
<!-- ============================================================ -->
The {{IDBKeyRange}} interface represents a
[=key range=].
<xmp class=idl>
[Exposed=(Window,Worker)]
interface IDBKeyRange {
readonly attribute any lower;
readonly attribute any upper;
readonly attribute boolean lowerOpen;
readonly attribute boolean upperOpen;
// Static construction methods:
[NewObject] static IDBKeyRange only(any value);
[NewObject] static IDBKeyRange lowerBound(any lower, optional boolean open = false);
[NewObject] static IDBKeyRange upperBound(any upper, optional boolean open = false);
[NewObject] static IDBKeyRange bound(any lower,
any upper,
optional boolean lowerOpen = false,
optional boolean upperOpen = false);
boolean _includes(any key);
};
</xmp>
<div class=note>
<dl class=domintro>
<dt><var>range</var> . {{IDBKeyRange/lower}}</dt>
<dd>
Returns [=lower bound=], or `undefined` if none.
</dd>
<dt><var>range</var> . {{IDBKeyRange/upper}}</dt>
<dd>
Returns [=upper bound=], or `undefined` if none.
</dd>
<dt><var>range</var> . {{IDBKeyRange/lowerOpen}}</dt>
<dd>
Returns true if the [=lower open flag=] is set, and false otherwise.
</dd>
<dt><var>range</var> . {{IDBKeyRange/upperOpen}}</dt>
<dd>
Returns true if the [=upper open flag=] is set, and false otherwise.
</dd>
</dl>
</div>
The <dfn attribute for=IDBKeyRange>lower</dfn> attribute's getter must
return result of running the steps to [=convert a key to a value=]
with the [=lower bound=] if it is not null, or undefined otherwise.
The <dfn attribute for=IDBKeyRange>upper</dfn> attribute's getter must
return the result of running the steps to [=convert a key to a
value=] with the [=upper bound=] if it is not null, or undefined
otherwise.
The <dfn attribute for=IDBKeyRange>lowerOpen</dfn> attribute's getter
must return true if the [=lower open flag=] is set, and false
otherwise.
The <dfn attribute for=IDBKeyRange>upperOpen</dfn> attribute's getter
must return true if the [=upper open flag=] is set, and false
otherwise.
<div class=note>
<dl class=domintro>
<dt><var>range</var> = {{IDBKeyRange}} .
{{IDBKeyRange/only()|only}}(<var>key</var>)</dt>
<dd>
Returns a new {{IDBKeyRange}} spanning only |key|.
</dd>
<dt><var>range</var> = {{IDBKeyRange}} .
{{IDBKeyRange/lowerBound()|lowerBound}}(<var>key</var> [, <var>open</var> = false])</dt>
<dd>
Returns a new {{IDBKeyRange}} starting at |key| with no
upper bound. If |open| is true, |key| is not included in the
range.
</dd>
<dt><var>range</var> = {{IDBKeyRange}} .
{{IDBKeyRange/upperBound()|upperBound}}(<var>key</var> [, <var>open</var> = false])</dt>
<dd>
Returns a new {{IDBKeyRange}} with no lower bound and ending at
|key|. If |open| is true, |key| is not included in the range.
</dd>
<dt><var>range</var> = {{IDBKeyRange}} .
{{IDBKeyRange/bound()|bound}}(<var>lower</var>, <var>upper</var>
[, <var>lowerOpen</var> = false
[, <var>upperOpen</var> = false]])</dt>
<dd>
Returns a new {{IDBKeyRange}} spanning from |lower| to |upper|.
If |lowerOpen| is true, |lower| is not included in the range.
If |upperOpen| is true, |upper| is not included in the range.
</dd>
</dl>
</div>
<div class=algorithm>
The <dfn method for=IDBKeyRange>only(|value|)</dfn> method, when
invoked, must run these steps:
1. Let |key| be the result of running the steps to [=convert
a value to a key=] with |value|. Rethrow any exceptions.
1. If |key| is invalid, [=throw=] a "{{DataError}}" {{DOMException}}.
1. Create and return a new [=key range=] [=containing only=]
|key|.
</div>
<div class=algorithm>
The <dfn method for=IDBKeyRange>lowerBound(|lower|, |lowerOpen|)</dfn>
method, when invoked, must run these steps:
1. Let |lowerKey| be the result of running the steps to [=convert a
value to a key=] with |lower|. Rethrow any exceptions.
1. If |lowerKey| is invalid, [=throw=] a "{{DataError}}" {{DOMException}}.
1. Create and return a new [=key range=] with [=lower bound=]
set to |lowerKey|, [=lower open flag=] set if |lowerOpen| is
true, [=upper bound=] set to null and [=upper open flag=]
set.
</div>
<div class=algorithm>
The <dfn method for=IDBKeyRange>upperBound(|upper|, |upperOpen|)</dfn>
method, when invoked, must run these steps:
1. Let |upperKey| be the result of running the steps to [=convert a
value to a key=] with |upper|. Rethrow any exceptions.
1. If |upperKey| is invalid, [=throw=] a "{{DataError}}" {{DOMException}}.
1. Create and return a new [=key range=] with [=lower bound=]
set to null, [=lower open flag=] set, [=upper bound=] set if
|upperKey|, and [=upper open flag=] set to |upperOpen|.
</div>
<div class=algorithm>
The <dfn method for=IDBKeyRange>bound(|lower|, |upper|, |lowerOpen|,
|upperOpen|)</dfn> method, when invoked, must run these steps:
1. Let |lowerKey| be the result of running the steps to [=convert a
value to a key=] with |lower|. Rethrow any exceptions.
1. If |lowerKey| is invalid, [=throw=] a "{{DataError}}" {{DOMException}}.
1. Let |upperKey| be the result of running the steps to [=convert a
value to a key=] with |upper|. Rethrow any exceptions.
1. If |upperKey| is invalid, [=throw=] a "{{DataError}}" {{DOMException}}.
1. If |lowerKey| is [=greater than=] |upperKey|, [=throw=] a
"{{DataError}}" {{DOMException}}.
1. Create and return a new [=key range=] with [=lower bound=]
set to |lowerKey|, [=lower open flag=] set if |lowerOpen| is
true, [=upper bound=] set to |upperKey| and [=upper open
flag=] set if |upperOpen| is true.
</div>
<div class=note>
<dl class=domintro>
<dt><var>range</var> .
{{IDBKeyRange/includes()|includes}}(<var>key</var>)</dt>
<dd>
Returns true if |key| is included in the range, and false otherwise.
</dd>
</dl>
</div>
<div class=algorithm>
The <dfn method for=IDBKeyRange>includes(|key|)</dfn> method, when
invoked, must run these steps:
1. Let |k| be the result of running the steps to [=convert a
value to a key=] with |key|. Rethrow any exceptions.
1. If |k| is invalid, [=throw=] a "{{DataError}}" {{DOMException}}.
1. Return true if |k| is [=in=]
this range, and false otherwise.
</div>
<!-- ============================================================ -->
## The {{IDBCursor}} interface ## {#cursor-interface}
<!-- ============================================================ -->
[=Cursor=] objects implement the {{IDBCursor}} interface. There
is only ever one {{IDBCursor}} instance representing a given
[=cursor=]. There is no limit on how many cursors can be used at
the same time.
<xmp class=idl>
[Exposed=(Window,Worker)]
interface IDBCursor {
readonly attribute (IDBObjectStore or IDBIndex) source;
readonly attribute IDBCursorDirection direction;
readonly attribute any key;
readonly attribute any primaryKey;
void advance([EnforceRange] unsigned long count);
void continue(optional any key);
void continuePrimaryKey(any key, any primaryKey);
[NewObject] IDBRequest update(any value);
[NewObject] IDBRequest delete();
};
enum IDBCursorDirection {
"next",
"nextunique",
"prev",
"prevunique"
};
</xmp>
<div class=note>
<dl class=domintro>
<dt><var>cursor</var> . {{IDBCursor/source}}</dt>
<dd>
Returns the {{IDBObjectStore}} or {{IDBIndex}} the cursor was opened from.
</dd>
<dt><var>range</var> . {{IDBCursor/direction}}</dt>
<dd>
Returns the [=cursor/direction=]
({{"next"}}, {{"nextunique"}}, {{"prev"}} or {{"prevunique"}})
of the cursor.
</dd>
<dt><var>cursor</var> . {{IDBCursor/key}}
<dd>
Returns the [=cursor/key=] of the cursor.
Throws a "{{InvalidStateError}}" {{DOMException}} if the cursor is advancing or is finished.
</dd>
<dt><var>cursor</var> . {{IDBCursor/primaryKey}}
<dd>
Returns the [=cursor/effective key=] of the cursor.
Throws a "{{InvalidStateError}}" {{DOMException}} if the cursor is advancing or is finished.
</dd>
</dl>
</div>
The <dfn attribute for=IDBCursor>source</dfn> attribute's getter must
return the [=cursor/source=] of this [=cursor=]. This
attribute never returns null or throws an exception, even if the
cursor is currently being iterated, has iterated past its end, or its
[=/transaction=] is not [=transaction/active=].