This is the Third Edition of Indexed Database API.
The
First Edition
simply titled "Indexed Database API",
became a W3C Recommendation on 8 January 2015.
The
Second Edition
titled "Indexed Database API 2.0",
became a W3C Recommendation on 30 January 2018.
Indexed Database API 3.0 is intended to supersede Indexed Database API 2.0.
1.
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.
The following example uses the API to access a
"library"
database. It has a
"books"
object store that holds books records stored by their
"isbn"
property as the primary key.
Book records have a
"title"
property. This example artificially requires that book titles are unique. The code enforces this by creating an index named
"by_title"
with the
unique
option set. This index is used to look up books by title, and will prevent adding books with non-unique titles.
Book records also have an
"author"
property, which is not
required
to be unique. The code creates another index named
"by_author"
to allow look-ups by this property.
The code first opens a connection to the database. The
upgradeneeded
event handler code creates the object store and indexes, if needed. The
success
event handler code saves the opened connection for use in later examples.
const
request
indexedDB
open
"library"
);
let
db
request
onupgradeneeded
function
()
// The database did not previously exist, so create object stores and indexes.
const
db
request
result
const
store
db
createObjectStore
"books"
keyPath
"isbn"
});
const
titleIndex
store
createIndex
"by_title"
"title"
unique
true
});
const
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.
const
tx
db
transaction
"books"
"readwrite"
);
const
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.
const
tx
db
transaction
"books"
"readonly"
);
const
store
tx
objectStore
"books"
);
const
index
store
index
"by_title"
);
const
request
index
get
"Bedrock Nights"
);
request
onsuccess
function
()
const
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.
const
tx
db
transaction
"books"
"readonly"
);
const
store
tx
objectStore
"books"
);
const
index
store
index
"by_author"
);
const
request
index
openCursor
IDBKeyRange
only
"Fred"
));
request
onsuccess
function
()
const
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 one way to handle errors when a request fails.
const
tx
db
transaction
"books"
"readwrite"
);
const
store
tx
objectStore
"books"
);
const
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.
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.
const
request
indexedDB
open
"library"
);
// Request version 3.
let
db
request
onupgradeneeded
function
event
const
db
request
result
if
event
oldVersion
// Version 1 is the first version of the database.
const
store
db
createObjectStore
"books"
keyPath
"isbn"
});
const
titleIndex
store
createIndex
"by_title"
"title"
unique
true
});
const
authorIndex
store
createIndex
"by_author"
"author"
);
if
event
oldVersion
// Version 2 introduces a new index of books by year.
const
bookStore
request
transaction
objectStore
"books"
);
const
yearIndex
bookStore
createIndex
"by_year"
"year"
);
if
event
oldVersion
// Version 3 introduces a new object store for magazines with two indexes.
const
magazines
db
createObjectStore
"magazines"
);
const
publisherIndex
magazines
createIndex
"by_publisher"
"publisher"
);
const
frequencyIndex
magazines
createIndex
"by_frequency"
"frequency"
);
};
request
onsuccess
function
()
db
request
result
// db.version will be 3.
};
A single database can be used by multiple clients (pages and workers)
simultaneously — transactions ensure they don’t clash while reading and writing.
If a new client wants to upgrade the database (via the
upgradeneeded
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
versionchange
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:
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
close()
method. However, you need to make
sure your app is aware of this, as subsequent attempts to access the database
will fail.
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.
const
request
indexedDB
open
"library"
);
// Request version 4.
let
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.
2.
Constructs
name
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.
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.
Details
This matches the
sort()
method on an
Array
of
String
. 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.
2.1.
Database
Each
storage key
has an associated set of
databases
. A
database
has zero or more
object stores
which
hold the data stored in the database.
database
has a
name
which identifies it within a
specific
storage key
. The name is a
name
and stays constant for the lifetime of the database.
database
has a
version
. When a database is first
created, its
version
is 0 (zero).
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
database
has at most one associated
upgrade transaction
which is either null or an
upgrade transaction
, and is initially null.
2.1.1.
Database connection
Script does not interact with
databases
directly. Instead,
script has indirect access via a
connection
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.
connection
can only access
databases
associated with the
storage key
of the global scope from which the
connection
is
opened.
NOTE:
This is not affected by changes to the
Document
’s
domain
connection
has a
version
, which is set when
the
connection
is created. It remains constant for the
lifetime of the
connection
unless an
upgrade is aborted
, in which
case it is set to the previous version of the
database
. Once
the
connection
is closed the
version
does not change.
Each connection has a
close pending flag
which is initially
false.
When a
connection
is initially created it is in an opened
state. The connection can be
closed
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 its
close pending flag
is always set to true if
it hasn’t already been.
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
storage key
’s storage. If this occurs
the user agent must run
close a database connection
with the
connection
and with the
forced flag
set to true.
connection
has an
object store set
, 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
live
connection
’s
get the parent
algorithm returns
null.
An event with type
versionchange
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.
An event with type
close
will be fired at a
connection
if the connection is
closed
abnormally.
2.2.
Object store
An
object store
is the primary storage mechanism for
storing data in a
database
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
upgradeneeded
event. When a
new database is created it doesn’t contain any
object stores
An
object store
has a
list of records
which hold the
data stored in the object store. Each
record
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
name
, 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
key path
. If the
object store has a key path it is said to use
in-line keys
Otherwise it is said to use
out-of-line keys
An
object store
optionally has a
key generator
An object store can derive a
key
for a
record
from
one of three sources:
key generator
. A key generator generates a monotonically
increasing numbers every time a key is needed.
Keys can be derived via a
key path
Keys can also be explicitly specified when a
value
is stored
in the object store.
2.2.1.
Object store handle
Script does not interact with
object stores
directly. Instead,
within a
transaction
, script has indirect access via an
object store handle
2.3.
Values
Each record is associated with a
value
. 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
StructuredSerializeForStorage
operation.
2.4.
Keys
In order to efficiently retrieve
records
stored in an indexed
database, each
record
is organized according to its
key
key
has an associated
type
which is one of:
number
date
string
binary
or
array
key
also has an associated
value
, which will
be either:
an
unrestricted double
if type is
number
or
date
DOMString
if type is
string
byte sequence
if type is
binary
or a
list
of other
keys
if type is
array
An ECMAScript
[ECMA-262]
value can be converted to a
key
by
following the steps to
convert a value to a key
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.
An
array key
is a
key
with
type
array
The
subkeys
of an
array key
are the
items
of the
array key
’s
value
To
compare two keys
and
, run these steps:
Let
ta
be the
type
of
Let
tb
be the
type
of
If
ta
does not equal
tb
, then run these steps:
If
ta
is
array
, then return 1.
If
tb
is
array
, then return -1.
If
ta
is
binary
, then return 1.
If
tb
is
binary
, then return -1.
If
ta
is
string
, then return 1.
If
tb
is
string
, then return -1.
If
ta
is
date
, then return 1.
Assert
tb
is
date
Return -1.
Let
va
be the
value
of
Let
vb
be the
value
of
Switch on
ta
number
date
If
va
is greater than
vb
, then return 1.
If
va
is less than
vb
, then return -1.
Return 0.
string
If
va
is
code unit less than
vb
, then return -1.
If
vb
is
code unit less than
va
, then return 1.
Return 0.
binary
If
va
is
byte less than
vb
, then return -1.
If
vb
is
byte less than
va
, then return 1.
Return 0.
array
Let
length
be the lesser of
va
’s
size
and
vb
’s
size
Let
be 0.
While
is less than
length
, then:
Let
be the result of recursively
comparing two keys
with
va
] and
vb
].
If
is not 0, return
Increase
by 1.
If
va
’s
size
is greater than
vb
’s
size
, then return 1.
If
va
’s
size
is less than
vb
’s
size
, then return -1.
Return 0.
The
key
is
greater than
the
key
if the
result of
comparing two keys
with
and
is 1.
The
key
is
less than
the
key
if the
result of
comparing two keys
with
and
is -1.
The
key
is
equal to
the
key
if the result
of
comparing two keys
with
and
is 0.
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.
NOTE:
Members of
binary
keys are compared as unsigned
byte
values
(in the range 0 to 255 inclusive) rather than signed
byte
values (in the range
-128 to 127 inclusive).
2.5.
Key path
key path
is a string or list of strings
that defines how to extract a
key
from a
value
. A
valid key path
is one of:
An empty string.
An
identifier
, 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.
NOTE:
Spaces are not allowed within a key path.
Key path
values can only be accessed from properties explicitly
copied by
StructuredSerializeForStorage
, as well as the
following type-specific properties:
2.6.
Index
It is sometimes useful to retrieve
records
in an
object store
through other means than their
key
. An
index
allows looking up
records
in an
object store
using properties of the
values
in the
object stores
records
An index is a specialized persistent key-value storage and has a
referenced
object store
. The
index has a
list of records
which hold the data stored in
the index. The
records
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
values
in the index’s
records
are always values of
keys
in the index’s
referenced
object store. The
keys
are derived from
the referenced object store’s
values
using a
key path
If a given
record
with key
in the object store referenced by
the index has the value
, and the index’s
key path
on
yields the result
, then the index will contain a record
with key
and value
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
key path
is "
name
" then the index would contain a record with
the key "
Alice
" and the value
123
Records in an index are said to have a
referenced value
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
key
is
and value is
has a
referenced value
of
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" }
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.
The
records
in an index are always sorted according to the
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
record
’s value
(meaning the key of the record in the referenced
object store
).
An
index
has a
name
, which is a
name
At any one time, the name is
unique within index’s
referenced
object store
An
index
has a
unique flag
. When
true, the index enforces that no two
records
in the index has
the same key. If a
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
multiEntry flag
. This flag affects how
the index behaves when the result of evaluating the index’s
key path
yields an
array key
. If its
multiEntry flag
is false, then a single
record
whose
key
is an
array key
is added to the index. If its
multiEntry flag
is true, then
one
record
is added to the index for each of the
subkeys
2.6.1.
Index handle
Script does not interact with
indexes
directly. Instead, within
transaction
, script has indirect access via an
index
handle
2.7.
Transactions
transaction
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
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
connection
transaction
has a
scope
which is a
set
of
object stores
that the transaction may interact with.
NOTE:
transaction
’s
scope
remains fixed unless the
transaction
is an
upgrade transaction
Two
transactions
have
overlapping scope
if any
object store
is in both transactions'
scope
transaction
has a
mode
that determines which types
of interactions can be performed upon that transaction. The
mode
is set when the transaction is created and remains fixed for the life
of the transaction. A
transaction
’s
mode
is one of the
following:
readonly
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 be
started
at the same time even
if their
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.
readwrite
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 be
started
at the same time if their
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.
versionchange
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
upgradeneeded
event is fired.
transaction
has a
durability hint
. This is a hint to the user agent of whether to prioritize performance or durability when committing the transaction. The
durability hint
is one of the following:
strict
The user agent may consider that the
transaction
has successfully
committed
only after verifying that all outstanding changes have been successfully written to a persistent storage medium.
relaxed
The user agent may consider that the
transaction
has successfully
committed
as soon as all outstanding changes have been written to the operating system, without subsequent verification.
default
The user agent should use its default durability behavior for the
storage bucket
. This is the default for
transactions
if not otherwise specified.
NOTE:
In a typical implementation, "
strict
" is a hint to the user agent to flush any operating system I/O buffers before a
complete
event is fired. While this provides greater confidence that the changes will be persisted in case of subsequent operating system crash or power loss, flushing buffers can take significant time and consume battery life on portable devices.
Web applications are encouraged to use "
relaxed
" for ephemeral data such as caches or quickly changing records, and "
strict
" in cases where reducing the risk of data loss outweighs the impact to performance and power. Implementations are encouraged to weigh the durability hint from applications against the impact to users and devices.
transaction
optionally has a
cleanup event loop
which is an
event loop
transaction
has a
request list
of pending
requests
which have been made against the transaction.
transaction
has a
error
which is set if the
transaction
is
aborted
NOTE:
Implementors need to keep in mind that the value "null" is considered an error, as it is set from
abort()
transaction
’s
get the parent
algorithm returns the
transaction’s
connection
read-only transaction
is
transaction
with
mode
readonly
".
read/write transaction
is a
transaction
with
mode
readwrite
".
2.7.1.
Transaction lifecycle
transaction
has a
state
, which is one
of the following:
active
A transaction is in this state when it is first
created
and during dispatch of an event from a
request
associated with the transaction.
New
requests
can be made against the transaction when it is in this state.
inactive
A transaction is in this state after control returns to the event
loop after its creation, and when events are not being dispatched.
No
requests
can be made against the transaction when it is in this state.
committing
Once all
requests
associated with a transaction have completed,
the transaction will enter this state as it attempts to
commit
No
requests
can be made against the transaction when it is in this state.
finished
Once a transaction has committed or aborted, it enters this state.
No
requests
can be made against the transaction when it is in this state.
Transactions are expected to be short lived. This is encouraged by the
automatic committing
functionality
described below.
NOTE:
Authors can still cause transactions to stay
alive
for a long time;
however, this usage pattern is not advised as it can lead to a poor
user experience.
The
lifetime
of a
transaction
is as follows:
A transaction is
created
with a
scope
and a
mode
. When a transaction is created its
state
is initially
active
When an implementation is able to enforce the constraints for the
transaction’s
scope
and
mode
defined
below
, the implementation must
queue a database task
to
start
the
transaction asynchronously.
Once the transaction has been
started
the
implementation can begin executing the
requests
placed
against the transaction. 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.
NOTE:
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.
When each
request
associated with a transaction is
processed
success
or
error
event
will be
fired. While the event is being
dispatched
, the transaction
state
is set to
active
, allowing
additional requests to be made against the transaction. Once the
event dispatch is complete, the transaction’s
state
is set to
inactive
again.
A transaction can be
aborted
at any time before it is
finished
, even if the
transaction isn’t currently
active
or hasn’t yet
started
An explicit call to
abort()
will initiate an
abort
. An abort will also be initiated following a
failed request that is not handled by script.
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
The implementation must attempt to
commit
an
inactive
transaction when all
requests
placed against the
transaction have completed and their returned results handled, no
new requests have been placed against the transaction, and the
transaction has not been
aborted
An explicit call to
commit()
will initiate a
commit
without waiting for request results to be
handled by script.
When committing, the transaction
state
is set to
committing
. 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,
and the steps to
abort a transaction
will be followed.
When a transaction is
committed
or
aborted
its
state
is set to
finished
The implementation must allow
requests
to be
placed
against the transaction whenever it is
active
. This is
the case even if the transaction has not yet been
started
. Until the transaction is
started
the implementation must not execute these
requests; however, the implementation must keep track of the
requests
and their order.
transaction
is said to be
live
from when it is
created
until its
state
is set to
finished
NOTE:
These steps are invoked by
[HTML]
. They ensure that
transactions
created by a script call
to
transaction()
are deactivated once the task that
invoked the script has completed. The steps are run at most once for
each
transaction
An event with type
complete
is fired at
transaction
that has successfully
committed
An event with type
abort
is fired at
transaction
that has
aborted
2.7.2.
Transaction scheduling
The following constraints define when a
transaction
can be
started
Implementations may impose additional constraints. For example, implementations are not required to
start
non-
overlapping
read/write transactions
in parallel, or may impose limits on the number of
started
transactions.
NOTE:
These constraints imply the following:
Any number of
read-only transactions
are allowed to be
started
concurrently, even if they have
overlapping scopes
As long as a
read-only transaction
is
live
, the data that the implementation returns through
requests
created with that transaction remains constant. That is, two requests to read the same piece of data 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.
read/write transaction
is only affected by changes to
object stores
that are made using the transaction itself. The implementation ensures that another transaction does not modify the contents of
object stores
in the
read/write transaction
’s
scope
. The implementation also ensures that if the
read/write transaction
completes successfully, the changes written to
object stores
using the transaction can be committed to the
database
without merge conflicts.
If multiple
read/write transactions
are attempting to access the same object store (i.e. if they have
overlapping scopes
), the transaction that was
created
first is the transaction which gets access to the object store first, and it is the only transaction which has access to the object store until the transaction is
finished
Any transaction
created
after a
read/write transaction
sees the changes written by the
read/write transaction
. For example, if a
read/write transaction
A, is created, and later another transaction B, is created, and the two transactions have
overlapping scopes
, then transaction B sees any changes made to any
object stores
that are part of that
overlapping scope
. This also means that transaction B does not have access to any
object stores
in that overlapping
scope
until transaction A is
finished
2.7.3.
Upgrade transactions
An
upgrade transaction
is a
transaction
with
mode
versionchange
".
An
upgrade transaction
is automatically created when running the
steps to
upgrade a database
after a
connection
is opened to a
database
, if a
version
greater than
the current
version
is specified. This
transaction
will be active inside the
upgradeneeded
event
handler.
2.8.
Requests
Each asynchronous operation on a
database
is done using a
request
. Every request represents one
operation.
request
has a
processed flag
which is initially false.
This flag is set to true when the operation associated with the request has been executed.
request
is said to be
processed
when its
processed flag
is true.
request
has a
done flag
which is initially false.
This flag is set to true when the result of the operation associated with the request is available.
request
has a
source
object.
request
has a
result
and an
error
, neither
of which are accessible until its
done flag
is true.
request
has a
transaction
which is initially null.
This will be set when a request is
placed
against a
transaction
using the steps to
asynchronously execute a request
When a request is made, a new
request
is returned with its
done flag
set to false. If a request completes successfully, its
done flag
is set to true, its
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’s
done flag
is set to true, the request’s
error
is set to the error, and an event with
type
error
is fired at the request.
request
’s
get the parent
algorithm returns the request’s
transaction
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
upgradeneeded
event and final result of the open operation itself. In some cases,
the request’s
done flag
will be set to false, then set to true again, and the
result
can change or
error
could be set instead.
2.8.1.
Open requests
An
open request
is a special type of
request
used
when opening a
connection
or deleting a
database
In addition to
success
and
error
events,
blocked
and
upgradeneeded
events may be fired at an
open request
to indicate progress.
The
source
of an
open request
is always null.
The
transaction
of an
open request
is null
unless an
upgradeneeded
event has been fired.
An
open request
’s
get the parent
algorithm returns null.
2.8.2.
Connection queues
Open requests
are processed in a
connection queue
The queue contains all
open requests
associated with an
storage key
and a
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
close
before the request can complete and allow
further requests to be processed.
NOTE:
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.
2.9.
Key range
Records can be retrieved from
object stores
and
indexes
using either
keys
or
key ranges
. A
key range
is a
continuous interval over some data type used for keys.
key range
containing only
key
has both
lower bound
and
upper bound
equal to
key
key
is
in a key range
range
if both of the following
conditions are fulfilled:
An
unbounded key range
is a
key range
that has both
lower bound
and
upper bound
equal to null. All
keys
are
in
an
unbounded key range
potentially valid key range
is an ECMAScript value that has a type that is convertible to a
key range
Whether the specific value will successfully convert to a
key range
, i.e.
converting a value to a key range
with it throws an exception, is not relevant.
NOTE:
For example, a
detached BufferSource
is a
potentially valid key range
that will throw an exception when used with
convert a value to a key range
To determine when a value
is a potentially valid key range
with ECMAScript
value
, run these steps:
If
value
is a
key range
, return true.
Let
key
be the result of
converting a value to a key
with
value
If
key
is "invalid type" return false.
Else return true.
2.10.
Cursor
cursor
is used to iterate over a range of records in an
index
or an
object store
in a specific direction.
cursor
has a
source handle
, which is the
index handle
or the
object store handle
that opened the cursor.
cursor
has a
transaction
, which is the
transaction
from the cursor’s
source handle
cursor
has a
range
of records in either an
index
or an
object store
cursor
has a
source
, which is an
index
or an
object store
from the cursor’s
source handle
The cursor’s
source
indicates which
index
or
object store
is associated with the records over which the
cursor
is iterating.
If the cursor’s
source handle
is an
index handle
, then the cursor’s
source
is
the index handle’s associated index
Otherwise, cursor’s
source
is
the object store handle’s associated object store
cursor
has a
direction
that determines whether it
moves in monotonically increasing or decreasing order of the
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
source
or at its end. A cursor’s
direction
is one of the following:
next
This direction causes the cursor to be opened at the start of the
source
. When iterated, the
cursor
should yield all
records, including duplicates, in monotonically increasing order
of keys.
nextunique
This direction causes the cursor to be opened at the start of the
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
source
is an
object store
or an
index
with
its
unique flag
set to true, this direction has exactly the same
behavior as "
next
".
prev
This direction causes the cursor to be opened at the end of the
source
. When iterated, the
cursor
should yield all
records, including duplicates, in monotonically decreasing order
of keys.
prevunique
This direction causes the cursor to be opened at the end of the
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
source
is an
object store
or an
index
with its
unique flag
set to true, this direction
has exactly the same behavior as "
prev
".
cursor
has a
position
within its range. It is
possible for the list of records which the cursor is iterating over to
change before the full
range
of the cursor has been iterated.
In order to handle this, cursors maintain their
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
object store position
, which
indicates the
value
of the previously found
record
in
the index. Both
position
and the
object store position
are used when finding the next appropriate record.
cursor
has a
key
and a
value
which
represent the
key
and the
value
of the last iterated
record
cursor
has a
got value flag
. When this flag is false,
the cursor is either in the process of loading the next value or it
has reached the end of its
range
. When it is true, it indicates
that the cursor is currently holding a value and that it is ready to
iterate to the next one.
If the
source
of a cursor is an
object store
, the
effective object store
of the cursor is that object store
and the
effective key
of the cursor is the cursor’s
position
. If the
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
cursor
has a
request
, which is the
request
used
to open the cursor.
cursor
also has a
key only flag
, that indicates
whether the cursor’s
value
is exposed via the API.
2.11.
Key generators
When a
object store
is created it can be specified to use a
key generator
. A key generator is used to generate keys
for records inserted into an object store if not otherwise specified.
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.
Modifying a key generator’s
current number
is considered part
of a database operation. This means that if the operation fails
and the operation is reverted, the
current number
is
reverted to the value it had before the operation started. This
applies both to modifications that happen due to the
current number
getting increased by 1 when the key generator is used,
and to modifications that happen due to a
record
being
stored with a key value specified in the call to store the
record
Likewise, if a
transaction
is aborted, the
current number
of the key generator for each
object store
in
the transaction’s
scope
is reverted to the value it had
before the
transaction
was started.
The
current number
for a key generator never decreases, other
than as a result of database operations being reverted. Deleting a
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
clear()
method, does not
affect the
current number
of the object store’s key
generator.
When a
record
is stored and a
key
is not specified
in the call to store the record, a key is generated.
When a
record
is stored and a
key
is specified
in the call to store the record, the associated
key generator
may
be updated.
To
possibly update the key generator
for an
object store
store
with
key
run these steps:
If the
type
of
key
is not
number
, abort these steps.
Let
value
be the
value
of
key
Set
value
to the minimum of
value
and 2
53
(9007199254740992).
Set
value
to the largest integer not greater than
value
Let
generator
be
store
’s
key generator
If
value
is greater than or equal to
generator
’s
current number
then set
generator
’s
current number
to
value
+ 1.
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
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
record
Only specified keys of
type
number
can affect the
current number
of the key generator. Keys of
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
current number
of the key generator. Keys of
type
number
with
value
less than 1 do not affect the
current number
since they are always lower than the
current number
When the
current number
of a key generator reaches above the
value 2
53
(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
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.
NOTE:
This limit arises because integers greater than 9007199254740992
cannot be uniquely represented as ECMAScript
Number
s.
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.
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.
Each object store gets its own key generator:
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.
transaction
onerror
function
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
clear()
is called.
store
db
createObjectStore
"store1"
autoIncrement
true
});
store
put
"a"
);
// Will get key 1
store
delete
);
store
put
"b"
);
// Will get key 2
store
clear
();
store
put
"c"
);
// Will get key 3
store
delete
IDBKeyRange
lowerBound
));
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.
store
db
createObjectStore
"store1"
autoIncrement
true
});
store
put
"a"
);
// Will get key 1
store
put
"b"
);
// 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.
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
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:
Then the value provided by the
key generator
is used to populate
the key value. In the example below the
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
const
store
db
createObjectStore
"store"
keyPath
"foo.bar"
autoIncrement
true
});
store
put
({
foo
{}
}).
onsuccess
function
const
key
target
result
console
assert
key
===
);
};
If the following conditions are true:
Then the value associated with the
key path
property is used. The auto-generated
key
is not used. In the
example below the
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.
const
store
db
createObjectStore
"store"
keyPath
"foo.bar"
autoIncrement
true
});
store
put
({
foo
bar
10
}).
onsuccess
function
const
key
target
result
console
assert
key
===
10
);
};
The following example illustrates the scenario when the specified
in-line
key
is defined through a
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
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.
const
store
db
createObjectStore
"store"
keyPath
"foo.bar.baz"
autoIncrement
true
});
store
put
({
zip
{}
}).
onsuccess
function
const
key
target
result
console
assert
key
===
);
store
get
key
).
onsuccess
function
const
value
target
result
// value will be: { zip: {}, foo: { bar: { baz: 1 } } }
console
assert
value
foo
bar
baz
===
);
};
};
Attempting to store a property on a primitive value will fail and
throw an error. In the first example below the
key path
for the object store is "
foo
". The actual object
is a primitive with the value,
. Trying to define a
property on that primitive value fails.
const
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
);
// will throw DataError
2.12.
Record snapshot
record snapshot
contains keys and values copied from an
object store record
or an
index record
3.
Exceptions
Each of the exceptions used in this document is a
DOMException
or
DOMException
-derived interface, as defined in
[WEBIDL]
The table below lists the
DOMException
names used in this
document along with a description of the exception’s
usage.
Type
Description
AbortError
A request was aborted.
ConstraintError
A mutation operation in the transaction failed because a
constraint was not satisfied.
DataCloneError
The data being stored could not be cloned by the internal
structured cloning algorithm.
DataError
Data provided to an operation does not meet requirements.
InvalidAccessError
An invalid operation was performed on an object.
InvalidStateError
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.
NotFoundError
The operation failed because the requested database object could
not be found.
NotReadableError
The operation failed because the underlying storage containing
the requested data could not be read.
SyntaxError
The keyPath argument contains an invalid key path.
ReadOnlyError
The mutating operation was attempted in a read-only transaction.
TransactionInactiveError
A request was placed against a transaction which is currently
not active, or which is finished.
UnknownError
The operation failed for transient reasons unrelated to the
database itself or not covered by any other error.
VersionError
An attempt was made to open a database using a lower version
than the existing version.
Apart from the above
DOMException
names, the
QuotaExceededError
exception type is to be used if 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.
NOTE:
Given that multiple Indexed DB operations can throw the same type of
error, and that even a 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.
4.
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
task source
for these tasks is the
database access task source
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.
In the following example, we open a
database
asynchronously.
Various event handlers are registered for responding to various
situations.
const
request
indexedDB
open
'AddressBook'
15
);
request
onsuccess
function
evt
{...};
request
onerror
function
evt
{...};
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"
};
request
result
When a request is completed, returns the
result
or
undefined
if the request failed. Throws a
InvalidStateError
DOMException
if the request is still pending.
request
error
When a request is completed, returns the
error
(a
DOMException
), or null if the request succeeded. Throws
a "
InvalidStateError
DOMException
if the request is still pending.
request
source
Returns the
IDBObjectStore
IDBIndex
, or
IDBCursor
the request was made against, or null if it was an
open request
request
transaction
Returns the
IDBTransaction
the request was made within.
If this as an
open request
, then it returns an
upgrade transaction
while it is
live
, or null otherwise.
request
readyState
Returns "
pending
" until a request is complete,
then returns "
done
".
The
source
getter steps are to
return
this
’s
source
, or null if no
source
is set.
The
transaction
getter steps are to
return
this
’s
transaction
NOTE:
The
transaction
getter can return null for certain requests, such as for
requests
returned from
open()
The
readyState
getter steps are to
return "
pending
" if
this
’s
done flag
is false, and
done
" otherwise.
The
onsuccess
attribute is an
event handler IDL attribute
whose
event handler event type
is
success
The
onerror
attribute is an
event handler IDL attribute
whose
event handler event type
is
error
event.
Methods on
IDBDatabase
that return a
open request
use an
extended interface to allow listening to the
blocked
and
upgradeneeded
events.
Exposed
=(
Window
Worker
)]
interface
IDBOpenDBRequest
IDBRequest
// Event handlers:
attribute
EventHandler
onblocked
attribute
EventHandler
onupgradeneeded
};
The
onblocked
attribute is an
event handler IDL attribute
whose
event handler event type
is
blocked
The
onupgradeneeded
attribute is an
event handler IDL attribute
whose
event handler event type
is
upgradeneeded
4.2.
Event interfaces
This specification fires events with the following custom interfaces:
Exposed
=(
Window
Worker
)]
interface
IDBVersionChangeEvent
Event
constructor
DOMString
type
optional
IDBVersionChangeEventInit
eventInitDict
= {});
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
};
The
oldVersion
getter steps are to return the value it was initialized to. It represents the previous version of the database.
The
newVersion
getter steps are to return the value it was initialized to. It represents the new version of the database, or null if the database is being deleted. See the steps to
upgrade a database
Events are constructed as defined in
DOM
§ 2.5 Constructing events
To
fire a version change event
named
at
target
given
oldVersion
and
newVersion
, run these steps:
Let
event
be the result of
creating an event
using
IDBVersionChangeEvent
Set
event
’s
type
attribute to
Set
event
’s
bubbles
and
cancelable
attributes to false.
Set
event
’s
oldVersion
attribute to
oldVersion
Set
event
’s
newVersion
attribute to
newVersion
Let
legacyOutputDidListenersThrowFlag
be false.
Dispatch
event
at
target
with
legacyOutputDidListenersThrowFlag
Return
legacyOutputDidListenersThrowFlag
NOTE:
The return value of this algorithm is not always used.
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.
partial
interface
mixin
WindowOrWorkerGlobalScope
SameObject
readonly
attribute
IDBFactory
indexedDB
};
The
indexedDB
attribute provides applications a mechanism for accessing capabilities
of indexed databases.
Exposed
=(
Window
Worker
)]
interface
IDBFactory
NewObject
IDBOpenDBRequest
open
DOMString
name
optional
EnforceRange
unsigned
long
long
version
);
NewObject
IDBOpenDBRequest
deleteDatabase
DOMString
name
);
Promise
sequence
IDBDatabaseInfo
>>
databases
();
short
cmp
any
first
any
second
);
};
dictionary
IDBDatabaseInfo
DOMString
name
unsigned
long
long
version
};
request
= indexedDB .
open
name
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
result
will be the
connection
request
= indexedDB .
open
name
version
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
blocked until they all 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
result
will
be the
connection
request
= indexedDB .
deleteDatabase
name
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
blocked until they all close. If the request
is successful
request
’s
result
will be null.
result
= await indexedDB .
databases
()
Returns a promise which resolves to a list of objects giving a snapshot
of the names and versions of databases within the
storage key
This API is intended for web applications to introspect the use of databases,
for example to clean up from earlier versions of a site’s code. Note that
the result is a snapshot; there are no guarantees about the sequencing of the
collection of the data or the delivery of the response with respect to requests
to create, upgrade, or delete databases by this context or others.
The
open(
name
version
method steps are:
If
version
is 0 (zero),
throw
TypeError
Let
environment
be
this
’s
relevant settings object
Let
storageKey
be the result of running
obtain a storage key
given
environment
If failure is returned, then
throw
a "
SecurityError
DOMException
and abort these steps.
Let
request
be a new
open request
Run these steps
in parallel
Let
result
be the result of
opening a database connection
, with
storageKey
name
version
if given and undefined
otherwise, and
request
What happens if
version
is not given?
If
version
is not given and a
database
with that name already exists, a connection will be opened
without changing the
version
. If
version
is not given and no
database
with
that name exists, a new
database
will be created with
version
equal to 1.
Set
request
’s
processed flag
to true.
Queue a database task
to run these steps:
If
result
is an error, then:
Set
request
’s
result
to undefined.
Set
request
’s
error
to
result
Set
request
’s
done flag
to true.
Fire an event
named
error
at
request
with its
bubbles
and
cancelable
attributes initialized to true.
Otherwise:
Set
request
’s
result
to
result
Set
request
’s
done flag
to true.
Fire an event
named
success
at
request
NOTE:
If the steps above resulted in an
upgrade transaction
being run, these steps will run after
that transaction finishes. This ensures that in the
case where 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.
Why aren’t the steps to
fire a success event
or
fire an error event
used?
There is no transaction associated with the request (at
this point), so those steps — which activate an
associated transaction before dispatch and deactivate
the transaction after dispatch — do not apply.
Return a new
IDBOpenDBRequest
object for
request
The
deleteDatabase(
name
method steps are:
Let
environment
be
this
’s
relevant settings object
Let
storageKey
be the result of running
obtain a storage key
given
environment
If failure is returned, then
throw
a "
SecurityError
DOMException
and abort these steps.
Let
request
be a new
open request
Run these steps
in parallel
Let
result
be the result of
deleting a database
, with
storageKey
name
, and
request
Set
request
’s
processed flag
to true.
Queue a database task
to run these steps:
If
result
is an error,
set
request
’s
error
to
result
set
request
’s
done flag
to true,
and
fire an event
named
error
at
request
with
its
bubbles
and
cancelable
attributes initialized to true.
Otherwise,
set
request
’s
result
to undefined,
set
request
’s
done flag
to true,
and
fire a version change event
named
success
at
request
with
result
and
null.
Why aren’t the steps to
fire a success event
or
fire an error event
used?
There is no transaction associated with the request, so
those steps — which activate an associated
transaction before dispatch and deactivate the
transaction after dispatch — do not apply.
Also, the
success
event here is a
IDBVersionChangeEvent
which includes the
oldVersion
and
newVersion
details.
Return a new
IDBOpenDBRequest
object for
request
The
databases()
method is new in this edition.
It is supported in Chrome 71, Edge 79, Firefox 126, and Safari 14.
result
= indexedDB .
cmp
key1
key2
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
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 false 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
closed
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",
optional
IDBTransactionOptions
options
= {});
undefined
close
();
NewObject
IDBObjectStore
createObjectStore
DOMString
name
optional
IDBObjectStoreParameters
options
= {});
undefined
deleteObjectStore
DOMString
name
);
// Event handlers:
attribute
EventHandler
onabort
attribute
EventHandler
onclose
attribute
EventHandler
onerror
attribute
EventHandler
onversionchange
};
enum
IDBTransactionDurability
"default"
"strict"
"relaxed"
};
dictionary
IDBTransactionOptions
IDBTransactionDurability
durability
= "default";
};
dictionary
IDBObjectStoreParameters
DOMString
or
sequence
DOMString
>)?
keyPath
null
boolean
autoIncrement
false
};
The
name
getter steps are to
return
this
’s associated
database
’s
name
NOTE:
The
name
attribute returns this name even if
this
’s
close pending flag
is true. In
other words, the value of this attribute stays constant for the
lifetime of the
IDBDatabase
instance.
The
version
getter steps are to
return
this
’s
version
Is this the same as the
database
’s
version
As long as the
connection
is open, this is the same as the
connected
database
’s
version
. But once the
connection
has
closed
, this attribute will not
reflect changes made with a later
upgrade transaction
Is this the same as the
database
’s
object store
names
As long as the
connection
is open, this is the same as the
connected
database
’s
object store
names
But once the
connection
has
closed
, this attribute
will not reflect changes made with a later
upgrade transaction
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
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
must be used as
error.
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
objectStoreNames
property on the
IDBDatabase
instance on which it was called.
The
transaction(
storeNames
mode
options
method steps are:
If a
live
upgrade transaction
is associated with the
connection
throw
an "
InvalidStateError
DOMException
If
this
’s
close pending flag
is true, then
throw
an
InvalidStateError
DOMException
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.
If any string in
scope
is not the name of an
object store
in the
connected
database
throw
NotFoundError
DOMException
If
scope
is empty,
throw
an "
InvalidAccessError
DOMException
If
mode
is not "
readonly
" or "
readwrite
",
throw
TypeError
Let
transaction
be a newly
created
transaction
with this
connection
mode
options
durability
member, and the set of
object stores
named in
scope
Set
transaction
’s
cleanup event loop
to the
current
event loop
Return an
IDBTransaction
object representing
transaction
The
durability
option is new in this edition.
It is supported in Chrome 82, Edge 82, Firefox 126, and Safari 15.
NOTE:
The created
transaction
will follow the
lifetime
rules.
NOTE:
The
connection
will not actually
close
until all outstanding
transactions
have completed. Subsequent calls to
close()
will have no effect.
The
onabort
attribute is an
event handler IDL attribute
whose
event handler event type
is
abort
The
onclose
attribute is an
event handler IDL attribute
whose
event handler event type
is
close
The
onerror
attribute is an
event handler IDL attribute
whose
event handler event type
is
error
The
onversionchange
attribute is an
event handler IDL attribute
whose
event handler event type
is
versionchange
The
IDBObjectStore
interface represents an
object store handle
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
queryOrOptions
optional
EnforceRange
unsigned
long
count
);
NewObject
IDBRequest
getAllKeys
optional
any
queryOrOptions
optional
EnforceRange
unsigned
long
count
);
NewObject
IDBRequest
getAllRecords
optional
IDBGetAllOptions
options
= {});
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
= {});
undefined
deleteIndex
DOMString
name
);
};
dictionary
IDBIndexParameters
boolean
unique
false
boolean
multiEntry
false
};
dictionary
IDBGetAllOptions
any
query
null
EnforceRange
unsigned
long
count
IDBCursorDirection
direction
= "next";
};
The
name
getter steps are to return
this
’s
name
Is this the same as the
object store
’s
name
As long as the
transaction
has not
finished
this is the same as the associated
object store
’s
name
. But once the
transaction
has
finished
, this attribute will not reflect changes made with a
later
upgrade transaction
The
keyPath
getter steps are to
return
this
’s
object store
’s
key path
, or
null if none. The
key path
is converted as a
DOMString
(if a
string) or a
sequence
DOMString
(if a list of strings), per
[WEBIDL]
NOTE:
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
Is this the same as
object store
’s list
of
index
names
As long as the
transaction
has not
finished
this is the same as the associated
object store
’s list
of
index
names
. But once the
transaction
has
finished
, this attribute will not
reflect changes made with a later
upgrade transaction
The
transaction
getter steps are to
return
this
’s
transaction
The
autoIncrement
getter steps are to
return true if
this
’s
object store
has a
key generator
and false otherwise.
The
put(
value
key
method steps are to return the result of running
add or put
with
this
value
key
and the
no-overwrite flag
false.
The
add(
value
key
method steps are to return the result of running
add or put
with
this
value
key
and the
no-overwrite flag
true.
To
add or put
with
handle
value
key
, and
no-overwrite flag
, run these steps:
Let
transaction
be
handle
’s
transaction
Let
store
be
handle
’s
object store
If
store
has been deleted,
throw
an "
InvalidStateError
DOMException
If
transaction
’s
state
is not
active
then
throw
a "
TransactionInactiveError
DOMException
If
transaction
is a
read-only transaction
throw
a "
ReadOnlyError
DOMException
If
store
uses
in-line keys
and
key
was given,
throw
a "
DataError
DOMException
If
store
uses
out-of-line keys
and has no
key generator
and
key
was not given,
throw
DataError
DOMException
If
key
was given, then:
Let
be the result of
converting a value to a key
with
key
. Rethrow any exceptions.
If
is "invalid value" or "invalid type",
throw
a "
DataError
DOMException
Let
key
be
Let
targetRealm
be a user-agent defined
Realm
Let
clone
be a
clone
of
value
in
targetRealm
during
transaction
Rethrow any exceptions.
Why create a copy of the value?
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.
If
store
uses
in-line keys
, then:
Let
kpk
be the result of with
clone
and
store
’s
key path
. Rethrow any
exceptions.
If
kpk
is invalid,
throw
a "
DataError
DOMException
If
kpk
is not failure, let
key
be
kpk
Otherwise (
kpk
is failure):
If
store
does not have a
key generator
throw
a "
DataError
DOMException
If
check that a key could be injected into a value
with
clone
and
store
’s
key path
return
false,
throw
a "
DataError
DOMException
Let
operation
be an algorithm to run
store a record into an object store
with
store
clone
key
, and
no-overwrite flag
Return the result (an
IDBRequest
) of running
asynchronously execute a request
with
handle
and
operation
NOTE:
Unlike other methods which take keys or key ranges, this method does
not
allow null to be given as key. This is to
reduce the risk that a small bug would clear a whole object store.
The following methods throw a "
TransactionInactiveError
DOMException
if called
when the
transaction
is not
active
request
store
get
query
Retrieves the
value
of the first
record
matching the
given
key
or
key range
in
query
If successful,
request
’s
result
will be the
value
, or
undefined
if there was no matching
record
request
store
getKey
query
Retrieves the
key
of the first
record
matching the
given
key
or
key range
in
query
If successful,
request
’s
result
will be the
key
, or
undefined
if there was no matching
record
request
store
getAll
query
[,
count
])
request
store
getAll
({
query
count
direction
})
Retrieves the
values
of the
records
matching the given
key
or
key range
in
query
(up to
count
if given).
Set the
direction
option to "
next
" to retrieve the first
count
values, or "
prev
" to return the last
count
values.
If successful,
request
’s
result
will be an
Array
of the
values
request
store
getAllKeys
query
[,
count
])
request
store
getAllKeys
({
query
count
direction
})
Retrieves the
keys
of
records
matching the given
key
or
key range
in
query
(up to
count
if given).
Set the
direction
option to "
next
" to retrieve the first
count
keys, or "
prev
" to return the last
count
keys.
If successful,
request
’s
result
will be an
Array
of the
keys
request
store
getAllRecords
({
query
count
direction
})
Retrieves the
keys
and
values
of
records
The
query
option specifies a
key
or
key range
to match.
The
count
option limits the number of records matched.
Set the
direction
option to "
next
" to retrieve the first
count
records, or "
prev
" to return the last
count
records.
If successful,
request
’s
result
will be an
Array
, with each member being an
IDBRecord
request
store
count
query
Retrieves the number of
records
matching the
given
key
or
key range
in
query
If successful,
request
’s
result
will be the count.
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
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.
The following methods throw a "
TransactionInactiveError
DOMException
if called
when the
transaction
is not
active
request
store
openCursor
([
query
[,
direction
= "next"]])
Opens a
cursor
over the
records
matching
query
ordered by
direction
. If
query
is null, all
records
in
store
are matched.
If successful,
request
’s
result
will be an
IDBCursorWithValue
pointing at the first matching
record
, or null if there were no matching
records
request
store
openKeyCursor
([
query
[,
direction
= "next"]])
Opens a
cursor
with
key only flag
set to true over the
records
matching
query
, ordered by
direction
. If
query
is null, all
records
in
store
are matched.
If successful,
request
’s
result
will be an
IDBCursor
pointing at the first matching
record
, or
null if there were no matching
records
The
openCursor(
query
direction
method steps are:
Let
transaction
be
this
’s
transaction
Let
store
be
this
’s
object store
If
store
has been deleted,
throw
an
InvalidStateError
DOMException
If
transaction
’s
state
is not
active
then
throw
a "
TransactionInactiveError
DOMException
Let
range
be the result of
converting a value to a key range
with
query
Rethrow any exceptions.
Let
cursor
be a new
cursor
with its
source handle
set to
this
undefined
position
direction
set to
direction
got value flag
set to false,
undefined
key
and
value
range
set to
range
, and
key only flag
set to false.
Let
operation
be an algorithm to run
iterate a cursor
with
the current Realm record
and
cursor
Let
request
be the result of running
asynchronously execute a request
with
this
and
operation
Set
cursor
’s
request
to
request
Return
request
NOTE:
The
query
parameter can be a
key
or
key range
(an
IDBKeyRange
to use as the
cursor
’s
range
If null or not given, an
unbounded key range
is used.
The
openKeyCursor(
query
direction
method steps are:
Let
transaction
be
this
’s
transaction
Let
store
be
this
’s
object store
If
store
has been deleted,
throw
an
InvalidStateError
DOMException
If
transaction
’s
state
is not
active
then
throw
a "
TransactionInactiveError
DOMException
Let
range
be the result of
converting a value to a key range
with
query
Rethrow any exceptions.
Let
cursor
be a new
cursor
with its
source handle
set to
this
undefined
position
direction
set to
direction
got value flag
set to false,
undefined
key
and
value
range
set to
range
, and
key only flag
set to true.
Let
operation
be an algorithm to run
iterate a cursor
with
the current Realm record
and
cursor
Let
request
be the result of running
asynchronously execute a request
with
this
and
operation
Set
cursor
’s
request
to
request
Return
request
NOTE:
The
query
parameter can be a
key
or
key range
(an
IDBKeyRange
to use as the
cursor
’s
range
. If null
or not given, an
unbounded key range
is used.
The
createIndex(
name
keyPath
options
method steps are:
Let
transaction
be
this
’s
transaction
Let
store
be
this
’s
object store
If
transaction
is not an
upgrade transaction
throw
an "
InvalidStateError
DOMException
If
store
has been deleted,
throw
an
InvalidStateError
DOMException
If
transaction
’s
state
is not
active
then
throw
a "
TransactionInactiveError
DOMException
If an
index
named
name
already exists in
store
throw
ConstraintError
DOMException
If
keyPath
is not a
valid key path
throw
a "
SyntaxError
DOMException
Let
unique
be
options
’s
unique
member.
Let
multiEntry
be
options
’s
multiEntry
member.
If
keyPath
is a sequence and
multiEntry
is
true,
throw
an "
InvalidAccessError
DOMException
Let
index
be a new
index
in
store
Set
index
’s
name
to
name
key path
to
keyPath
unique flag
to
unique
, and
multiEntry flag
to
multiEntry
Add
index
to
this
’s
index set
Return a new
index handle
associated with
index
and
this
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
key path
. If the
referenced
object store already contains data
which violates these constraints, this must not cause the
implementation of
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 database task
to abort the
upgrade transaction
which was
used for the
createIndex()
call.
This method synchronously modifies the
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 run the steps to
abort a transaction
using an appropriate error. For example
if creating the
index
failed due to quota reasons,
QuotaExceededError
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.
The asynchronous creation of indexes is observable in the following example:
const
request1
objectStore
put
({
name
"betty"
},
);
const
request2
objectStore
put
({
name
"betty"
},
);
const
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
uniqueness constraint
does not cause the second
request
to fail. Instead, the
transaction
will
be
aborted
when the index is created and the constraint
fails.
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.
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
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
4.6.
The
IDBIndex
interface
The
IDBIndex
interface represents an
index handle
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
queryOrOptions
optional
EnforceRange
unsigned
long
count
);
NewObject
IDBRequest
getAllKeys
optional
any
queryOrOptions
optional
EnforceRange
unsigned
long
count
);
NewObject
IDBRequest
getAllRecords
optional
IDBGetAllOptions
options
= {});
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");
};
The
name
getter steps are to
return
this
’s
name
Is this the same as the
index
’s
name
As long as the
transaction
has not
finished
this is the same as the associated
index
’s
name
. But once the
transaction
has
finished
, this attribute will not reflect changes made with a
later
upgrade transaction
The
objectStore
getter steps are to
return
this
’s
object store handle
The
keyPath
getter steps are to
return
this
’s
index
’s
key path
. The
key path
is converted as a
DOMString
(if a string) or a
sequence
DOMString
(if a
list of strings), per
[WEBIDL]
NOTE:
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
multiEntry
getter steps are to
return
this
’s
index
’s
multiEntry flag
The
unique
getter steps are to
return
this
’s
index
’s
unique flag
The following methods throw an "
TransactionInactiveError
DOMException
if called
when the
transaction
is not
active
request
index
get
query
Retrieves the
value
of the first
record
matching the
given
key
or
key range
in
query
If successful,
request
’s
result
will be the
value
, or
undefined
if there was no matching
record
request
index
getKey
query
Retrieves the
key
of the first
record
matching the
given
key
or
key range
in
query
If successful,
request
’s
result
will be the
key
, or
undefined
if there was no matching
record
request
index
getAll
query
[,
count
])
request
index
getAll
({
query
count
direction
})
Retrieves the
values
of the
records
matching the given
key
or
key range
in
query
(up to
count
if given).
Set the
direction
option to "
next
" to retrieve the first
count
values, "
prev
" to return the last
count
values.
Set the
direction
option to "
nextunique
" or "
prevunique
" to exclude records with duplicate index keys after retrieving the first record with the duplicate index key.
If successful,
request
’s
result
will be an
Array
of the
values
request
index
getAllKeys
query
[,
count
])
request
index
getAllKeys
({
query
count
direction
})
Retrieves the
keys
of
records
matching the given
key
or
key range
in
query
(up to
count
if given).
Set the
direction
option to "
next
" to retrieve the first
count
keys, "
prev
" to return the last
count
keys.
Set the
direction
option to "
nextunique
" or "
prevunique
" to exclude records with duplicate index keys after retrieving the first record with the duplicate index key.
If successful,
request
’s
result
will be an
Array
of the
keys
request
index
getAllRecords
({
query
count
direction
})
Retrieves the
keys
values
, and index
keys
of
records
The
query
option specifies a
key
or
key range
to match.
The
count
option limits the number of records matched.
Set the
direction
option to "
next
" to retrieve the first
count
records, "
prev
" to return the last
count
records.
Set the
direction
option to "
nextunique
" or "
prevunique
" to exclude records with duplicate index keys after retrieving the first record with the duplicate index key.
If successful,
request
’s
result
will be an
Array
, with each member being an
IDBRecord
. Use the
IDBRecord’s key
to get the record’s index
key
. Use the
IDBRecord’s primaryKey
to get the record’s
key
request
index
count
query
Retrieves the number of
records
matching the given
key
or
key range
in
query
If successful,
request
’s
result
will be the
count.
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
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.
The following methods throw an "
TransactionInactiveError
DOMException
if called
when the
transaction
is not
active
request
index
openCursor
([
query
[,
direction
= "next"]])
Opens a
cursor
over the
records
matching
query
ordered by
direction
. If
query
is null, all
records
in
index
are matched.
If successful,
request
’s
result
will be an
IDBCursorWithValue
, or null if there were no matching
records
request
index
openKeyCursor
([
query
[,
direction
= "next"]])
Opens a
cursor
with
key only flag
set to true over the
records
matching
query
, ordered by
direction
. If
query
is null, all
records
in
index
are matched.
If successful,
request
’s
result
will be an
IDBCursor
, or null if there were no matching
records
The
openCursor(
query
direction
method steps are:
Let
transaction
be
this
’s
transaction
Let
index
be
this
’s
index
If
index
or
index
’s
object store
has been deleted,
throw
an "
InvalidStateError
DOMException
If
transaction
’s
state
is not
active
then
throw
a "
TransactionInactiveError
DOMException
Let
range
be the result of
converting a value to a key range
with
query
Rethrow any exceptions.
Let
cursor
be a new
cursor
with its
source handle
set to
this
undefined
position
direction
set to
direction
got value flag
set to false,
undefined
key
and
value
range
set to
range
, and
key only flag
set to false.
Let
operation
be an algorithm to run
iterate a cursor
with
the current Realm record
and
cursor
Let
request
be the result of running
asynchronously execute a request
with
this
and
operation
Set
cursor
’s
request
to
request
Return
request
NOTE:
The
query
parameter can be a
key
or
key range
(an
IDBKeyRange
to use as the
cursor
’s
range
. If null
or not given, an
unbounded key range
is used.
The
openKeyCursor(
query
direction
method steps are:
Let
transaction
be
this
’s
transaction
Let
index
be
this
’s
index
If
index
or
index
’s
object store
has
been deleted,
throw
an "
InvalidStateError
DOMException
If
transaction
’s
state
is not
active
then
throw
a "
TransactionInactiveError
DOMException
Let
range
be the result of
converting a value to a key range
with
query
Rethrow any exceptions.
Let
cursor
be a new
cursor
with its
source handle
set to
this
undefined
position
direction
set to
direction
got value flag
set to false,
undefined
key
and
value
range
set to
range
, and
key only flag
set to true.
Let
operation
be an algorithm to run
iterate a cursor
with
the current Realm record
and
cursor
Let
request
be the result of running
asynchronously execute a request
with
this
and
operation
Set
cursor
’s
request
to
request
Return
request
NOTE:
The
query
parameter can be a
key
or
key range
(an
IDBKeyRange
to use as the
cursor
’s
range
. If null
or not given, an
unbounded key range
is used.
The
IDBKeyRange
interface represents a
key range
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
);
};
The
lower
getter steps are to
return the result of
converting a key to a value
with
this
’s
lower bound
if it is not null, or undefined otherwise.
The
upper
getter steps are to
return the result of
converting a key to a value
with
this
’s
upper bound
if it is not null, or undefined
otherwise.
The
lowerOpen
getter steps are to
return
this
’s
lower open flag
The
upperOpen
getter steps are to
return
this
’s
upper open flag
range
IDBKeyRange
only
key
Returns a new
IDBKeyRange
spanning only
key
range
IDBKeyRange
lowerBound
key
[,
open
= false])
Returns a new
IDBKeyRange
starting at
key
with no
upper bound. If
open
is true,
key
is not included in the
range.
range
IDBKeyRange
upperBound
key
[,
open
= false])
Returns a new
IDBKeyRange
with no lower bound and ending at
key
. If
open
is true,
key
is not included in the range.
range
IDBKeyRange
bound
lower
upper
[,
lowerOpen
= false
[,
upperOpen
= false]])
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.
range
includes
key
Returns true if
key
is included in the range, and false otherwise.
4.8.
The
IDBRecord
interface
The
IDBRecord
interface represents a
record snapshot
Exposed
=(
Window
Worker
)]
interface
IDBRecord
readonly
attribute
any
key
readonly
attribute
any
primaryKey
readonly
attribute
any
value
};
The
key
getter steps are to return the result of
converting a key to a value
with
this
’s
key
The
primaryKey
getter steps are to return the result of
converting a key to a value
with
this
’s
primary key
The
value
getter steps are to return
this
’s
value
4.9.
The
IDBCursor
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.
Exposed
=(
Window
Worker
)]
interface
IDBCursor
readonly
attribute
IDBObjectStore
or
IDBIndex
source
readonly
attribute
IDBCursorDirection
direction
readonly
attribute
any
key
readonly
attribute
any
primaryKey
SameObject
readonly
attribute
IDBRequest
request
undefined
advance
([
EnforceRange
unsigned
long
count
);
undefined
continue
optional
any
key
);
undefined
continuePrimaryKey
any
key
any
primaryKey
);
NewObject
IDBRequest
update
any
value
);
NewObject
IDBRequest
delete
();
};
enum
IDBCursorDirection
"next"
"nextunique"
"prev"
"prevunique"
};
The
source
getter steps are to
return
this
’s
source handle
NOTE:
The
source
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
active
The
direction
getter steps are to
return
this
’s
direction
The
key
getter steps are to
return the result of
converting a key to a value
with the cursor’s current
key
NOTE:
If
key
returns an object (e.g. a
Date
or
Array
), it returns the same object instance every time it is
inspected, until the cursor’s
key
is changed. This
means that if the object is modified, those modifications will be seen
by anyone inspecting the value of the cursor. However modifying such
an object does not modify the contents of the database.
The
primaryKey
getter steps are to
return the result of
converting a key to a value
with the cursor’s current
effective key
NOTE:
If
primaryKey
returns an object (e.g. a
Date
or
Array
),
it returns the same object instance every time it is inspected, until
the cursor’s
effective key
is changed. This means that if the
object is modified, those modifications will be seen by anyone
inspecting the value of the cursor. However modifying such an object
does not modify the contents of the database.
The
request
getter steps are to
return
this
’s
request
The
request
attribute is new in this edition.
It is supported in Chrome 76, Edge 79, Firefox 77, and Safari 15.
NOTE:
Calling this method more than once before new cursor data has been
loaded - for example, calling
advance()
twice from the
same onsuccess handler - results in an "
InvalidStateError
DOMException
being thrown on the second call because the cursor’s
got value flag
has been set to false.
The
continue(
key
method steps are:
Let
transaction
be
this
’s
transaction
If
transaction
’s
state
is not
active
then
throw
a "
TransactionInactiveError
DOMException
If
this
’s
source
or
effective object store
has been deleted,
throw
an
InvalidStateError
DOMException
If
this
’s
got value flag
is false, indicating that
the cursor is being iterated or has iterated past its end,
throw
an "
InvalidStateError
DOMException
If
key
is given, then:
Let
be the result of
converting a value to a key
with
key
. Rethrow any exceptions.
If
is "invalid value" or "invalid type",
throw
a "
DataError
DOMException
Let
key
be
If
key
is
less than
or
equal to
this
’s
position
and
this
’s
direction
is
next
" or "
nextunique
", then
throw
a "
DataError
DOMException
If
key
is
greater than
or
equal to
this
’s
position
and
this
’s
direction
is
prev
" or "
prevunique
", then
throw
a "
DataError
DOMException
Set
this
’s
got value flag
to false.
Let
request
be
this
’s
request
Set
request
’s
processed flag
to false.
Set
request
’s
done flag
to false.
Let
operation
be an algorithm to run
iterate a cursor
with
the current Realm record
this
, and
key
(if given).
Run
asynchronously execute a request
with
this
’s
source handle
operation
, and
request
NOTE:
Calling this method more than once before new cursor data has been
loaded - for example, calling
continue()
twice from the
same onsuccess handler - results in an "
InvalidStateError
DOMException
being thrown on the second call because the cursor’s
got value flag
has been set to false.
The
continuePrimaryKey(
key
primaryKey
method steps are:
Let
transaction
be
this
’s
transaction
If
transaction
’s
state
is not
active
then
throw
a "
TransactionInactiveError
DOMException
If
this
’s
source
or
effective object store
has been deleted,
throw
an "
InvalidStateError
DOMException
If
this
’s
source
is not an
index
throw
an "
InvalidAccessError
DOMException
If
this
’s
direction
is not "
next
" or "
prev
",
throw
an "
InvalidAccessError
DOMException
If
this
’s
got value flag
is false, indicating that
the cursor is being iterated or has iterated past its end,
throw
an "
InvalidStateError
DOMException
Let
be the result of
converting a value to a key
with
key
. Rethrow any exceptions.
If
is "invalid value" or "invalid type",
throw
a "
DataError
DOMException
Let
key
be
Let
be the result of
converting a value to a key
with
primaryKey
. Rethrow any exceptions.
If
is "invalid value" or "invalid type",
throw
a "
DataError
DOMException
Let
primaryKey
be
If
key
is
less than
this
’s
position
and
this
’s
direction
is "
next
",
throw
a "
DataError
DOMException
If
key
is
greater than
this
’s
position
and
this
’s
direction
is "
prev
",
throw
a "
DataError
DOMException
If
key
is
equal to
this
’s
position
and
primaryKey
is
less than
or
equal to
this
’s
object store position
and
this
’s
direction
is
next
",
throw
a "
DataError
DOMException
If
key
is
equal to
this
’s
position
and
primaryKey
is
greater than
or
equal to
this
’s
object store position
and
this
’s
direction
is "
prev
",
throw
DataError
DOMException
Set
this
’s
got value flag
to false.
Let
request
be
this
’s
request
Set
request
’s
processed flag
to false.
Set
request
’s
done flag
to false.
Let
operation
be an algorithm to run
iterate a cursor
with
the current Realm record
this
key
, and
primaryKey
Run
asynchronously execute a request
with
this
’s
source handle
operation
, and
request
NOTE:
Calling this method more than once before new cursor data has been
loaded - for example, calling
continuePrimaryKey()
twice from
the same onsuccess handler - results in an "
InvalidStateError
DOMException
being thrown on the second call because the cursor’s
got value flag
has been set to false.
The
update(
value
method steps are:
Let
transaction
be
this
’s
transaction
If
transaction
’s
state
is not
active
then
throw
a "
TransactionInactiveError
DOMException
If
transaction
is a
read-only transaction
throw
ReadOnlyError
DOMException
If
this
’s
source
or
effective object store
has been deleted,
throw
an "
InvalidStateError
DOMException
If
this
’s
got value flag
is false, indicating that
the cursor is being iterated or has iterated past its end,
throw
an "
InvalidStateError
DOMException
If
this
’s
key only flag
is true,
throw
an
InvalidStateError
DOMException
Let
targetRealm
be a user-agent defined
Realm
Let
clone
be a
clone
of
value
in
targetRealm
during
transaction
Rethrow any exceptions.
Why create a copy of the value?
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.
If
this
’s
effective object store
uses
in-line keys
, then:
Let
kpk
be the result of
with
clone
and the
key path
of
this
’s
effective object store
Rethrow any exceptions.
If
kpk
is failure, invalid, or not
equal to
this
’s
effective key
throw
DataError
DOMException
Let
operation
be an algorithm to run
store a record into an object store
with
this
’s
effective object store
clone
this
’s
effective key
, and false.
Return the result (an
IDBRequest
) of running
asynchronously execute a request
with
this
and
operation
NOTE:
A result of
storing a record into an object store
is that if the record has been deleted since the cursor
moved to it, a new record will be created.
cursor
that has its
key only flag
set to false implements the
IDBCursorWithValue
interface as well.
Exposed
=(
Window
Worker
)]
interface
IDBCursorWithValue
IDBCursor
readonly
attribute
any
value
};
The
value
getter steps are to
return
this
’s current
value
NOTE:
If
value
returns an object, it returns the same object
instance every time it is inspected, until the cursor’s
value
is changed. This means that if the object is
modified, those modifications will be seen by anyone inspecting the
value of the cursor. However modifying such an object does not modify
the contents of the database.
Transaction
objects implement the following interface:
Exposed
=(
Window
Worker
)]
interface
IDBTransaction
EventTarget
readonly
attribute
DOMStringList
objectStoreNames
readonly
attribute
IDBTransactionMode
mode
readonly
attribute
IDBTransactionDurability
durability
SameObject
readonly
attribute
IDBDatabase
db
readonly
attribute
DOMException
error
IDBObjectStore
objectStore
DOMString
name
);
undefined
commit
();
undefined
abort
();
// Event handlers:
attribute
EventHandler
onabort
attribute
EventHandler
oncomplete
attribute
EventHandler
onerror
};
enum
IDBTransactionMode
"readonly"
"readwrite"
"versionchange"
};
NOTE:
The contents of each list returned by this attribute does not
change, but subsequent calls to this attribute during an
upgrade transaction
can return lists with different contents as
object stores
are created and deleted.
The
mode
getter steps are to
return
this
’s
mode
The
durability
getter steps are to return
this
’s
durability hint
The
durability
attribute is new in this edition.
It is supported in Chrome 82, Edge 82, Firefox 126, and Safari 15.
The
db
getter steps are to
return
this
’s
connection
’s associated
database
The
error
getter steps are to
return
this
’s
error
, or null if
none.
NOTE:
If this
transaction
was aborted due to a failed
request
, this will be the same as the
request
’s
error
. If this
transaction
was aborted
due to an uncaught exception in an event handler, the error will be
a "
AbortError
DOMException
. If the
transaction
was aborted due to
an error while committing, it will reflect the reason for the
failure (e.g. a
QuotaExceededError
, or a "
ConstraintError
" or
UnknownError
DOMException
).
transaction
objectStore
name
Returns an
IDBObjectStore
in the
transaction
’s
scope
transaction
abort()
Aborts the transaction. All pending
requests
will fail with
a "
AbortError
DOMException
and all changes made to the database will be
reverted.
transaction
commit()
Attempts to commit the transaction. All pending
requests
will be allowed
to complete, but no new requests will be accepted. This can be used to force a
transaction to quickly finish, without waiting for pending requests to fire
success
events before attempting to commit normally.
The transaction will abort if a pending request fails, for example due to a
constraint error. The
success
events for successful requests
will still fire, but throwing an exception in an event handler will not abort
the transaction. Similarly,
error
events for failed requests
will still fire, but calling
preventDefault()
will not prevent the
transaction from aborting.
NOTE:
Each call to this method on the same
IDBTransaction
instance
with the same name returns the same
IDBObjectStore
instance.
NOTE:
The returned
IDBObjectStore
instance is specific to this
IDBTransaction
. If this method is called on a different
IDBTransaction
, a different
IDBObjectStore
instance is
returned.
The
commit()
method is new in this edition.
It is supported in Chrome 76, Edge 79, Firefox 74, and Safari 15.
NOTE:
It is not normally necessary to call
commit()
on a
transaction
. A transaction will automatically commit
when all outstanding requests have been satisfied and no new
requests have been made. This call can be used to start the
commit
process without waiting for events
from outstanding
requests
to be dispatched.
The
onabort
attribute is an
event handler IDL attribute
whose
event handler event type
is
abort
The
oncomplete
attribute is an
event handler IDL attribute
whose
event handler event type
is
complete
The
onerror
attribute is an
event handler IDL attribute
whose
event handler event type
is
error
NOTE:
To determine if a
transaction
has completed successfully,
listen to the
transaction
’s
complete
event
rather than the
success
event of a particular
request
, because the
transaction
can still fail after
the
success
event fires.
5.
Algorithms
5.1.
Opening a database connection
To
open a database connection
with
storageKey
which requested the
database
to be opened, a database
name
, a database
version
, and a
request
, run these steps:
Let
queue
be the
connection queue
for
storageKey
and
name
Add
request
to
queue
Wait until all previous requests in
queue
have been processed.
Let
db
be the
database
named
name
in
storageKey
, or null otherwise.
If
version
is undefined, let
version
be 1 if
db
is null, or
db
’s
version
otherwise.
If
db
is null, let
db
be a new
database
with
name
name
version
0 (zero), and with
no
object stores
. If this fails for any reason, return an
appropriate error (e.g. a
QuotaExceededError
, or an
UnknownError
DOMException
).
If
db
’s
version
is greater than
version
return a newly
created
VersionError
DOMException
and abort these steps.
Let
connection
be a new
connection
to
db
Set
connection
’s
version
to
version
If
db
’s
version
is less than
version
, then:
Let
openConnections
be the
set
of all
connections
except
connection
, associated with
db
For each
entry
of
openConnections
that does not have its
close pending flag
set to true,
queue a database task
to
fire a version change event
named
versionchange
at
entry
with
db
’s
version
and
version
NOTE:
Firing this event might cause one or more of the other
objects in
openConnections
to be closed, in which case the
versionchange
event is not fired at those
objects, even if that hasn’t yet been done.
Wait for all of the events to be fired.
If any of the
connections
in
openConnections
are still
not closed,
queue a database task
to
fire a version change event
named
blocked
at
request
with
db
’s
version
and
version
Wait
until all
connections
in
openConnections
are
closed
Run
upgrade a database
using
connection
version
and
request
If
connection
was
closed
return a newly
created
AbortError
DOMException
and abort these steps.
If
request
’s
error
is set, run the steps
to
close a database connection
with
connection
return a newly
created
AbortError
DOMException
and abort these steps.
Return
connection
5.2.
Closing a database connection
To
close a database connection
with a
connection
object, and an
optional
forced flag
, run these steps:
Set
connection
’s
close pending flag
to true.
If the
forced flag
is true, then for each
transaction
created
using
connection
run
abort a transaction
with
transaction
and newly
created
AbortError
DOMException
Wait for all transactions
created
using
connection
to complete.
Once they are complete,
connection
is
closed
If the
forced flag
is true, then
fire an event
named
close
at
connection
NOTE:
The
close
event only fires if the connection closes
abnormally, e.g. if the
storage key
’s storage is cleared, or there is
corruption or an I/O error. If
close()
is called explicitly
the event
does not
fire.
NOTE:
Once a
connection
’s
close pending flag
has been set to true, no new transactions
can be
created
using the
connection
. All methods that
create
transactions first check the
connection
’s
close pending flag
first and throw an exception if it is true.
NOTE:
Once the
connection
is closed, this can unblock the steps to
upgrade a database
, and the steps to
delete a database
, which
both
wait
for
connections
to
a given
database
to be closed before continuing.
5.3.
Deleting a database
To
delete a database
with the
storageKey
that
requested the
database
to be deleted, a database
name
, and a
request
, run these steps:
Let
queue
be the
connection queue
for
storageKey
and
name
Add
request
to
queue
Wait until all previous requests in
queue
have been processed.
Let
db
be the
database
named
name
in
storageKey
, if one exists. Otherwise, return 0 (zero).
Let
openConnections
be the
set
of all
connections
associated with
db
For each
entry
of
openConnections
that does not have its
close pending flag
set to true,
queue a database task
to
fire a version change event
named
versionchange
at
entry
with
db
’s
version
and null.
NOTE:
Firing this event might cause one or more of the other objects
in
openConnections
to be closed, in which case the
versionchange
event is not fired at those
objects, even if that hasn’t yet been done.
Wait for all of the events to be fired.
If any of the
connections
in
openConnections
are still not
closed,
queue a database task
to
fire a version change event
named
blocked
at
request
with
db
’s
version
and null.
Wait
until all
connections
in
openConnections
are
closed
Let
version
be
db
’s
version
Delete
db
. If this fails for any reason, return an appropriate
error (e.g. a
QuotaExceededError
, or an "
UnknownError
DOMException
).
Return
version
5.4.
Committing a transaction
5.5.
Aborting a transaction
To
abort a transaction
with the
transaction
to abort, and
error
, run these steps:
If
transaction
’s
state
is
finished
, abort these steps.
All the changes made to the
database
by the
transaction
are reverted. For
upgrade transactions
this includes changes
to the set of
object stores
and
indexes
, as well as the
change to the
version
. Any
object stores
and
indexes
which were created during the transaction are now
considered deleted for the purposes of other algorithms.
If
transaction
is an
upgrade transaction
, run the steps
to
abort an upgrade transaction
with
transaction
NOTE:
This reverts changes to all
connection
object store handle
, and
index handle
instances associated with
transaction
Set
transaction
’s
state
to
finished
Set
transaction
’s
error
to
error
For each
request
of
transaction
’s
request list
abort the steps to
asynchronously execute a request
for
request
set
request
’s
processed flag
to true,
and
queue a database task
to run these steps:
Set
request
’s
done flag
to true.
Set
request
’s
result
to undefined.
Set
request
’s
error
to a newly
created
AbortError
DOMException
Fire an event
named
error
at
request
with its
bubbles
and
cancelable
attributes initialized to true.
NOTE:
This does not always result in any
error
events
being fired. For example if a transaction is aborted due to an
error while
committing
the transaction,
or if it was the last remaining request that failed.
Queue a database task
to run these steps:
If
transaction
is an
upgrade transaction
, then set
transaction
’s
connection
’s associated
database
’s
upgrade transaction
to null.
Fire an event
named
abort
at
transaction
with its
bubbles
attribute initialized to true.
If
transaction
is an
upgrade transaction
, then:
Let
request
be the
open request
associated with
transaction
Set
request
’s
transaction
to null.
Set
request
’s
result
to undefined.
Set
request
’s
processed flag
to false.
Set
request
’s
done flag
to false.
5.6.
Asynchronously executing a
request
To
asynchronously execute a request
with the
source
object and an
operation
to perform on a database, and an optional
request
, run these steps:
These steps can be aborted at any point if the
transaction
the
created
request
belongs to is
aborted
using the steps to
abort a transaction
Let
transaction
be the
transaction
associated with
source
Assert
transaction
’s
state
is
active
If
request
was not given, let
request
be a new
request
with
source
as
source
Add
request
to the end of
transaction
’s
request list
Run these steps
in parallel
Wait until
request
is the first item in
transaction
’s
request list
that is not
processed
Let
result
be the result of performing
operation
If
result
is an error and
transaction
’s
state
is
committing
then run
abort a transaction
with
transaction
and
result
and terminate these steps.
If
result
is an error,
then revert all changes made by
operation
NOTE:
This only reverts the changes done by this request, not any
other changes made by the transaction.
Set
request
’s
processed flag
to true.
Queue a database task
to run these steps:
Remove
request
from
transaction
’s
request list
Set
request
’s
done flag
to true.
If
result
is an error, then:
Set
request
’s
result
to undefined.
Set
request
’s
error
to
result
Fire an error event
at
request
Otherwise:
Set
request
’s
result
to
result
Set
request
’s
error
to undefined.
Fire a success event
at
request
Return
request
5.7.
Upgrading a database
To
upgrade a database
with
connection
(a
connection
), a new
version
, and a
request
, run these steps:
Let
db
be
connection
’s
database
Let
transaction
be a new
upgrade transaction
with
connection
used as
connection
Set
transaction
’s
scope
to
connection
’s
object store set
Set
db
’s
upgrade transaction
to
transaction
Set
transaction
’s
state
to
inactive
Start
transaction
NOTE:
Note that until this
transaction
is finished, no
other
connections
can be opened to the same
database
Let
old version
be
db
’s
version
Set
db
’s
version
to
version
. This change is
considered part of the
transaction
, and so if the
transaction is
aborted
, this change is reverted.
Set
request
’s
processed flag
to true.
Queue a database task
to run these steps:
Set
request
’s
result
to
connection
Set
request
’s
transaction
to
transaction
Set
request
’s
done flag
to true.
Set
transaction
’s
state
to
active
Let
didThrow
be the result of
firing a version change event
named
upgradeneeded
at
request
with
old
version
and
version
If
transaction
’s
state
is
active
, then:
Set
transaction
’s
state
to
inactive
If
didThrow
is true, run
abort a transaction
with
transaction
and a newly
created
AbortError
DOMException
Wait for
transaction
to
finish
NOTE:
Some of the algorithms invoked during the
transaction
’s
lifetime
, such as the steps to
commit a transaction
and the steps to
abort a transaction
include steps specific to
upgrade transactions
5.8.
Aborting an upgrade transaction
To
abort an upgrade transaction
with
transaction
, run these steps:
NOTE:
These steps are run as needed by the steps to
abort a transaction
, which revert changes to the
database
including
the set of associated
object stores
and
indexes
, as well
as the change to the
version
Let
connection
be
transaction
’s
connection
Let
database
be
connection
’s
database
Set
connection
’s
version
to
database
’s
version
if
database
previously existed, or 0 (zero)
if
database
was newly created.
NOTE:
This reverts the value of
version
returned by the
IDBDatabase
object.
Set
connection
’s
object store set
to the set of
object stores
in
database
if
database
previously
existed, or the empty set if
database
was newly created.
NOTE:
This reverts the value of
objectStoreNames
returned
by the
IDBDatabase
object.
For each
object store handle
handle
associated with
transaction
, including those for
object stores
that
were created or deleted during
transaction
If
handle
’s
object store
was not
newly created during
transaction
, set
handle
’s
name
to its
object store
’s
name
Set
handle
’s
index set
to the set of
indexes
that
reference its
object store
NOTE:
This reverts the values of
name
and
indexNames
returned by related
IDBObjectStore
objects.
How is this observable?
Although script cannot access an
object store
by using the
objectStore()
method on an
IDBTransaction
instance after
the
transaction
is aborted, it can still have references to
IDBObjectStore
instances where the
name
and
indexNames
properties can be queried.
For each
index handle
handle
associated with
transaction
including those for
indexes
that were created or deleted
during
transaction
If
handle
’s
index
was not newly created
during
transaction
, set
handle
’s
name
to
its
index
’s
name
NOTE:
This reverts the value of
name
returned by related
IDBIndex
objects.
How is this observable?
Although script cannot access an
index
by using the
index()
method on an
IDBObjectStore
instance after the
transaction
is aborted, it can still have references to
IDBIndex
instances where the
name
property can
be queried.
NOTE:
The
name
property of the
IDBDatabase
instance is
not modified, even if the aborted
upgrade transaction
was
creating a new
database
5.9.
Firing a success event
5.10.
Firing an error event
5.11.
Clone a value
5.12.
Creating a request to retrieve multiple items
To
create a
request
to retrieve multiple items
from an
object store
or
index
with
targetRealm
sourceHandle
kind
queryOrOptions
, and optional
count
, run these steps:
Let
source
be an
index
or an
object store
from
sourceHandle
If
sourceHandle
is an
index handle
, then
source
is
the index handle’s associated index
Otherwise,
source
is
the object store handle’s associated object store
If
source
has been deleted,
throw
an "
InvalidStateError
DOMException
If
source
is an
index
and
source
’s
object store
has been deleted,
throw
an "
InvalidStateError
DOMException
Let
transaction
be
sourceHandle
’s
transaction
If
transaction
’s
state
is not
active
, then
throw
a "
TransactionInactiveError
DOMException
Let
range
be a
key range
Let
direction
be a
cursor direction
If running
is a potentially valid key range
with
queryOrOptions
is true, then:
Set
range
to the result of
converting a value to a key range
with
queryOrOptions
. Rethrow any exceptions.
Set
direction
to "
next
".
Else:
Set
range
to the result of
converting a value to a key range
with
queryOrOptions
["
query
"]. Rethrow any exceptions.
Set
count
to
queryOrOptions
["
count
"].
Set
direction
to
queryOrOptions
["
direction
"].
Let
operation
be an algorithm to run.
If
source
is an
index
, set
operation
to
retrieve multiple items from an index
with
targetRealm
source
range
kind
direction
, and
count
if given.
Else set
operation
to
retrieve multiple items from an object store
with
targetRealm
source
range
kind
direction
, and
count
if given.
Return the result (an
IDBRequest
) of running
asynchronously execute a request
with
sourceHandle
and
operation
NOTE:
The
range
can be a
key
or
key range
(an
IDBKeyRange
) identifying the
record
items 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.
6.
Database operations
This section describes various operations done on the data in
object stores
and
indexes
in a
database
These operations are run by the steps to
asynchronously execute a request
NOTE:
Invocations of
StructuredDeserialize
() in the operation
steps below can be asserted not to throw (as indicated by the
prefix)
because they operate only on previous output of
StructuredSerializeForStorage
().
6.1.
Object store storage operation
To
store a record into an object store
with
store
value
, an optional
key
, and a
no-overwrite flag
, run these steps:
If
store
uses a
key generator
, then:
If
key
is undefined, then:
Let
key
be the result of
generating a key
for
store
If
key
is failure, then this operation failed with a
ConstraintError
DOMException
. Abort this
algorithm without taking any further steps.
If
store
also uses
in-line keys
, then run
inject a key into a value using a key path
with
value
key
and
store
’s
key path
Otherwise, run
possibly update the key generator
for
store
with
key
If the
no-overwrite flag
was given to these steps and is true, and
record
already exists in
store
with its key
equal to
key
, then this operation failed with a "
ConstraintError
DOMException
Abort this algorithm without taking any further steps.
If a
record
already exists in
store
with its key
equal to
key
, then remove the
record
from
store
using
delete records from an object store
Store a record in
store
containing
key
as its key and
StructuredSerializeForStorage
value
as its value. The record is stored in the object store’s
list of records
such that the list is sorted
according to the key of the records in
ascending
order.
For each
index
which
references
store
Let
index key
be the result of
with
value
index
’s
key path
, and
index
’s
multiEntry flag
If
index key
is an exception, or invalid, or failure, take no
further actions for
index
, and continue these steps
for the next index.
NOTE:
An exception thrown in this step is not rethrown.
If
index
’s
multiEntry flag
is false, or if
index key
is not an
array key
, and if
index
already contains a
record
with
key
equal to
index
key
, and
index
’s
unique flag
is true, then this
operation failed with a "
ConstraintError
DOMException
. Abort this
algorithm without taking any further steps.
If
index
’s
multiEntry flag
is true and
index key
is
an
array key
, and if
index
already contains a
record
with
key
equal to
any of the
subkeys
of
index key
, and
index
’s
unique flag
is true, then this operation failed with a
ConstraintError
DOMException
. Abort this algorithm without taking any
further steps.
If
index
’s
multiEntry flag
is false, or if
index key
is not an
array key
then store a record in
index
containing
index key
as its key and
key
as its value. The
record is stored in
index
’s
list of records
such that the list is sorted primarily on the records keys,
and secondarily on the records values, in
ascending
order.
If
index
’s
multiEntry flag
is true and
index key
is
an
array key
, then for each
subkey
of the
subkeys
of
index key
store a record in
index
containing
subkey
as its key and
key
as its value. The
records are stored in
index
’s
list of records
such that the list is sorted primarily on the
records keys, and secondarily on the records values, in
ascending
order.
NOTE:
It is valid for there to be no
subkeys
. In this case
no records are added to the index.
NOTE:
Even if any member of
subkeys
is itself an
array key
the member is used directly as the key for the index record.
Nested
array keys
are not flattened or "unpacked" to
produce multiple rows; only the outer-most
array key
is.
Return
key
6.2.
Object store retrieval operations
To
retrieve a value from an object store
with
targetRealm
store
and
range
, run these steps.
They return undefined, an ECMAScript value, or an error (a
DOMException
):
Let
record
be the first
record
in
store
’s
list of records
whose
key
is
in
range
, if
any.
If
record
was not found, return undefined.
Let
serialized
be
record
’s
value
. If an error occurs while reading the value from the
underlying storage, return a newly
created
NotReadableError
DOMException
Return
StructuredDeserialize
serialized
targetRealm
).
To
retrieve a key from an object store
with
store
and
range
, run these steps:
Let
record
be the first
record
in
store
’s
list of records
whose
key
is
in
range
, if
any.
If
record
was not found, return undefined.
Return the result of
converting a key to a value
with
record
’s key.
To
retrieve multiple items from an object store
with
targetRealm
store
range
kind
direction
, and optional
count
, run these steps:
If
count
is not given or is 0 (zero), let
count
be infinity.
Let
records
be an empty
list
of
records
If
direction
is "
next
" or "
nextunique
", set
records
to the first
count
of
store
’s
list of records
whose
key
is
in
range
If
direction
is "
prev
" or "
prevunique
", set
records
to the last
count
of
store
’s
list of records
whose
key
is
in
range
Let
list
be an empty
list
For each
record
of
records
, switching on
kind
"key"
Let
key
be the result of
converting a key to a value
with
record
’s key.
Append
key
to
list
"value"
Let
serialized
be
record
’s
value
Let
value
be
StructuredDeserialize
serialized
targetRealm
).
Append
value
to
list
"record"
Let
key
be the
record
’s key.
Let
serialized
be
record
’s
value
Let
value
be
StructuredDeserialize
serialized
targetRealm
).
Let
recordSnapshot
be a new
record snapshot
with its
key
set to
key
value
set to
value
, and
primary key
set to
key
Append
recordSnapshot
to
list
Return
list
6.3.
Index retrieval operations
To
retrieve a referenced value from an index
with
targetRealm
index
and
range
, run these steps:
Let
record
be the first
record
in
index
’s
list of records
whose
key
is
in
range
, if any.
If
record
was not found, return undefined.
Let
serialized
be
record
’s
referenced value
Return
StructuredDeserialize
serialized
targetRealm
).
To
retrieve multiple items from an index
with
targetRealm
index
range
kind
direction
and optional
count
, run these steps:
If
count
is not given or is 0 (zero), let
count
be infinity.
Let
records
be an empty
list
of
records
Switching on
direction
"next"
Set
records
to the first
count
of
index
’s
list of records
whose
key
is
in
range
"nextunique"
Let
rangeRecords
be a list containing the
index
’s
list of records
whose
key
is
in
range
Let
rangeRecordsLength
be
rangeRecords
’s
size
Let
be 0.
While
is less than
rangeRecordsLength
, then:
Increase
by 1.
if
record
’s
size
is equal to
count
, then
break
If the result of
comparing two keys
using the keys from |rangeRecords[i]| and |rangeRecords[i-1]| is equal, then
continue
Else
append
|rangeRecords[i]| to
records
"prev"
Set
records
to the last
count
of
index
’s
list of records
whose
key
is
in
range
"prevunique"
Let
rangeRecords
be a list containing the
index
’s
list of records
whose
key
is
in
range
Let
rangeRecordsLength
be
rangeRecords
’s
size
Let
be 0.
While
is less than
rangeRecordsLength
, then:
Increase
by 1.
if
record
’s
size
is equal to
count
, then
break
If the result of
comparing two keys
using the keys from |rangeRecords[i]| and |rangeRecords[i-1]| is equal, then
continue
Else
prepend
|rangeRecords[i]| to
records
Let
list
be an empty
list
For each
record
of
records
, switching on
kind
"key"
Let
key
be the result of
converting a key to a value
with
record
’s value.
Append
key
to
list
"value"
Let
serialized
be
record
’s
referenced value
Let
value
be
StructuredDeserialize
serialized
targetRealm
).
Append
value
to
list
"record"
Let
index key
be the
record
’s key.
Let
key
be the
record
’s value.
Let
serialized
be
record
’s
referenced value
Let
value
be
StructuredDeserialize
serialized
targetRealm
).
Let
recordSnapshot
be a new
record snapshot
with its
key
set to
index key
value
set to
value
, and
primary key
set to
key
Append
recordSnapshot
to
list
Return
list
6.4.
Object store deletion operation
To
delete records from an object store
with
store
and
range
, run these steps:
Remove all records, if any, from
store
’s
list of records
with key
in
range
For each
index
which
references
store
, remove every
record
from
index
’s
list of records
whose value is
in
range
, if any such records exist.
Return undefined.
6.5.
Record counting operation
To
count the records in a range
with
source
and
range
, run these steps:
Let
count
be the number of records, if any, in
source
’s list of
records with key
in
range
Return
count
6.6.
Object store clear operation
To
clear an object store
with
store
, run these steps:
Remove all records from
store
In all
indexes
which
reference
store
, remove all
records
Return undefined.
6.7.
Cursor iteration operation
To
iterate a cursor
with
targetRealm
cursor
, an optional
key
and
primaryKey
to iterate to, and an optional
count
, run these steps:
Let
source
be
cursor
’s
source
Let
direction
be
cursor
’s
direction
Assert
: if
primaryKey
is given,
source
is an
index
and
direction
is "
next
" or "
prev
".
Let
records
be the list of
records
in
source
NOTE:
records
is always sorted in
ascending
key
order.
In the case of
source
being an
index
records
is secondarily sorted in
ascending
value
order
(where the value in an
index
is the
key
of the
record
in the referenced
object store
).
Let
range
be
cursor
’s
range
Let
position
be
cursor
’s
position
Let
object store position
be
cursor
’s
object store position
If
count
is not given, let
count
be 1.
While
count
is greater than 0:
Switch on
direction
next
Let
found record
be the first record in
records
which
satisfy all of the following requirements:
If
key
is defined:
If
primaryKey
is defined:
If
position
is defined and
source
is an
object store
If
position
is defined and
source
is an
index
The record’s key is
in
range
nextunique
Let
found record
be the first record in
records
which
satisfy all of the following requirements:
prev
Let
found record
be the last record in
records
which
satisfy all of the following requirements:
If
key
is defined:
If
primaryKey
is defined:
If
position
is defined and
source
is an
object store
If
position
is defined and
source
is an
index
The record’s key is
in
range
prevunique
Let
temp record
be the last record in
records
which satisfy all of the following requirements:
If
temp record
is defined, let
found record
be the
first record in
records
whose
key
is
equal to
temp record
’s
key
NOTE:
Iterating with "
prevunique
" visits the same records that
nextunique
" visits, but in reverse order.
If
found record
is not defined, then:
Set
cursor
’s
key
to undefined.
If
source
is an
index
, set
cursor
’s
object store position
to undefined.
If
cursor
’s
key only flag
is false, set
cursor
’s
value
to undefined.
Return null.
Let
position
be
found record
’s key.
If
source
is an
index
, let
object store
position
be
found record
’s value.
Decrease
count
by 1.
Set
cursor
’s
position
to
position
If
source
is an
index
, set
cursor
’s
object store position
to
object store position
Set
cursor
’s
key
to
found record
’s key.
If
cursor
’s
key only flag
is false, then:
Let
serialized
be
found record
’s
value
if
source
is an
object store
, or
found record
’s
referenced value
otherwise.
Set
cursor
’s
value
to
StructuredDeserialize
serialized
targetRealm
Set
cursor
’s
got value flag
to true.
Return
cursor
7.
ECMAScript binding
This section defines how
key
values defined in this specification
are converted to and from ECMAScript values, and how they may be
extracted from and injected into ECMAScript values using
key paths
. This section references types and algorithms and uses some
algorithm conventions from the ECMAScript Language Specification.
[ECMA-262]
Conversions not detailed here are defined in
[WEBIDL]
To
with
value
keyPath
and an optional
multiEntry flag
, run the
following steps. The result of these steps is a
key
, invalid, or
failure, or the steps may throw an exception.
Let
be the result of
evaluating a key path on a value
with
value
and
keyPath
. Rethrow any
exceptions.
If
is failure, return failure.
Let
key
be the result of
converting a value to a key
with
if the
multiEntry flag
is false, and the
result of
converting a value to a multiEntry key
with
otherwise. Rethrow any exceptions.
If
key
is "invalid value" or "invalid type", return invalid.
Return
key
To
evaluate a key path on a value
with
value
and
keyPath
, run the following steps. The result of these steps is an
ECMAScript value or failure, or the steps may throw an exception.
If
keyPath
is a
list
of strings, then:
Let
result
be a new
Array
object created as if by the
expression
[]
Let
be 0.
For each
item
of
keyPath
Let
key
be the result of recursively
evaluating a key path on a value
with
item
and
value
Assert
key
is not an
abrupt completion
If
key
is failure, abort the overall algorithm and return
failure.
Let
be
ToString
).
Let
status
be
CreateDataProperty
result
key
).
Assert
status
is true.
Increase
by 1.
Return
result
NOTE:
This will only ever "recurse" one level since
key path
sequences can’t ever be nested.
If
keyPath
is the empty string, return
value
and skip the
remaining steps.
Let
identifiers
be the result of
strictly splitting
keyPath
on U+002E FULL STOP characters (.).
For each
identifier
of
identifiers
, jump to the appropriate step below:
If
Type
value
) is String, and
identifier
is "
length
Let
value
be a Number equal to the number of elements in
value
If
value
is an
Array
and
identifier
is "
length
Let
value
be
ToLength
Get
value
, "
length
")).
If
value
is a
Blob
and
identifier
is "
size
Let
value
be a Number equal to
value
’s
size
If
value
is a
Blob
and
identifier
is "
type
Let
value
be a String equal to
value
’s
type
If
value
is a
File
and
identifier
is "
name
Let
value
be a String equal to
value
’s
name
If
value
is a
File
and
identifier
is "
lastModified
Let
value
be a Number equal to
value
’s
lastModified
Otherwise
If
Type
value
) is not Object, return failure.
Let
hop
be
HasOwnProperty
value
identifier
).
If
hop
is false, return failure.
Let
value
be
Get
value
identifier
).
If
value
is undefined, return failure.
Assert
value
is not an
abrupt completion
Return
value
NOTE:
Assertions can be made in the above steps because this algorithm is
only applied to values that are the output of
StructuredDeserialize
and only access "own" properties.
7.2.
Inject a key into a value
NOTE:
The
key paths
used in this section are always strings and never
sequences, since it is not possible to create a
object store
which has a
key generator
and also has a
key path
that is a
sequence.
To
check that a key could be injected into a value
with
value
and a
keyPath
, run the following steps.
The result of these steps is either true or false.
Let
identifiers
be the result of
strictly splitting
keyPath
on U+002E FULL STOP characters (.).
Assert
identifiers
is not empty.
Remove the last
item
of
identifiers
For each
remaining
identifier
of
identifiers
, if any:
If
value
is not an
Object
or an
Array
, return false.
Let
hop
be
HasOwnProperty
value
identifier
).
If
hop
is false, return true.
Let
value
be
Get
value
identifier
).
Return true if
value
is an
Object
or an
Array
, or false otherwise.
NOTE:
Assertions can be made in the above steps because this algorithm is
only applied to values that are the output of
StructuredDeserialize
NOTE:
Assertions can be made in the above steps because this algorithm is
only applied to values that are the output of
StructuredDeserialize
and the steps to
check that a key could be injected into a value
have
been run.
7.3.
Convert a key to a value
To
convert a key to a value
with
key
, run the following steps.
The steps return an ECMAScript value.
Let
type
be
key
’s
type
Let
value
be
key
’s
value
Switch on
type
number
Return an ECMAScript Number value equal to
value
string
Return an ECMAScript String value equal to
value
date
Let
date
be the result of executing the ECMAScript Date
constructor with the single argument
value
Assert
date
is not an
abrupt completion
Return
date
binary
Let
len
be
value
’s
length
Let
buffer
be the result of executing the ECMAScript
ArrayBuffer constructor with
len
Assert
buffer
is not an
abrupt completion
Set the entries in
buffer
’s
[[ArrayBufferData]] internal slot to the entries
in
value
Return
buffer
array
Let
array
be the result of executing the ECMAScript Array
constructor with no arguments.
Assert
array
is not an
abrupt completion
Let
len
be
value
’s
size
Let
index
be 0.
While
index
is less than
len
Let
entry
be the result of
converting a key to a value
with
value
index
].
Let
status
be
CreateDataProperty
array
index
entry
).
Assert
status
is true.
Increase
index
by 1.
Return
array
7.4.
Convert a value to a key
To
convert a value to a key
with an ECMAScript value
input
, and an optional
set
seen
, run the following steps.
The result of these steps is a
key
, or "invalid value", or "invalid type", or the
steps may throw an exception.
If
seen
was not given, then let
seen
be a new empty
set
If
seen
contains
input
, then return "invalid value".
Jump to the appropriate step below:
If
Type
input
) is Number
If
input
is NaN then return "invalid value".
Otherwise, return a new
key
with
type
number
and
value
input
If
input
is a
Date
(has a [[DateValue]] internal slot)
Let
ms
be the value of
input
’s
[[DateValue]] internal slot.
If
ms
is NaN then return "invalid value".
Otherwise, return a new
key
with
type
date
and
value
ms
If
Type
input
) is String
Return a new
key
with
type
string
and
value
input
If
input
is a
buffer source type
If
input
is
detached
then return "invalid value".
Let
bytes
be the result of
getting a copy of the bytes held by the buffer source
input
Return a new
key
with
type
binary
and
value
bytes
If
input
is an
Array exotic object
Let
len
be
ToLength
Get
input
length
")).
Append
input
to
seen
Let
keys
be a new empty list.
Let
index
be 0.
While
index
is less than
len
Let
hop
be
HasOwnProperty
input
index
).
If
hop
is false, return "invalid value".
Let
entry
be
Get
input
index
).
Let
key
be the result of
converting a value to a key
with arguments
entry
and
seen
ReturnIfAbrupt
key
).
If
key
is "invalid value" or "invalid type" abort these steps and return "invalid value".
Append
key
to
keys
Increase
index
by 1.
Return a new
array key
with
value
keys
Otherwise
Return "invalid type".
To
convert a value to a multiEntry key
with an ECMAScript value
input
, run the following steps.
The result of these steps is a
key
, or "invalid value", or "invalid type", or the steps may throw an exception.
If
input
is an
Array exotic object
, then:
Let
len
be
ToLength(
Get
input
, "
length
")).
Let
seen
be a new
set
containing only
input
Let
keys
be a new empty
list
Let
index
be 0.
While
index
is less than
len
Let
entry
be
Get
input
index
).
If
entry
is not an
abrupt completion
, then:
Let
key
be the result of
converting a value to a key
with arguments
entry
and
seen
If
key
is not "invalid value" or "invalid type" or an
abrupt completion
and there is no
item
in
keys
equal to
key
then
append
key
to
keys
Increase
index
by 1.
Return a new
array key
with
value
set to
keys
Otherwise, return the result of
converting a value to a key
with argument
input
Rethrow any exceptions.
NOTE:
These steps are similar to those to
convert a value to a key
but if the top-level value is an
Array
then members which can
not be converted to keys are ignored, and duplicates are removed.
For example, the value
[10, 20, null, 30, 20]
is
converted to an
array key
with
subkeys
10, 20, 30.
8.
Privacy considerations
This section is non-normative.
8.1.
User tracking
A third-party host (or any object capable of getting content
distributed to multiple sites) could use a unique identifier stored in
its client-side database to track a user across multiple sessions,
building a profile of the user’s activities. In conjunction with a
site that is aware of the user’s real id object (for example an
e-commerce site that requires authenticated credentials), this could
allow oppressive groups to target individuals with greater accuracy
than in a world with purely anonymous Web usage.
There are a number of techniques that can be used to mitigate the risk
of user tracking:
Blocking third-party storage
User agents may restrict access to the database objects
to scripts originating at the domain of the top-level document of
the
browsing context
, for instance denying access to
the API for pages from other domains running in
iframe
s.
Expiring stored data
User agents may automatically delete stored data after a period of
time.
This can restrict the ability of a site to track a user, as the site
would then only be able to track the user across multiple sessions
when she authenticates with the site itself (e.g. by making a purchase
or logging in to a service).
However, this also puts the user’s data at risk.
Treating persistent storage as cookies
User agents should present the database feature to the user in a way
that associates them strongly with HTTP session cookies.
[COOKIES]
This might encourage users to view such storage with healthy
suspicion.
Site-specific safe-listing of access to databases
User agents may require the user to authorize access to databases
before a site can use the feature.
Attribution of third-party storage
User agents may record the
origins
of sites that contained content
from third-party
origins
that caused data to be stored.
If this information is then used to present the view of data
currently in persistent storage, it would allow the user to make
informed decisions about which parts of the persistent storage to
prune. Combined with a blocklist ("delete this data and prevent
this domain from ever storing data again"), the user can restrict
the use of persistent storage to sites that she trusts.
Shared blocklists
User agents may allow users to share their persistent storage
domain blocklists.
This would allow communities to act together to protect their
privacy.
While these suggestions prevent trivial use of this API for user
tracking, they do not block it altogether. Within a single domain, a
site can continue to track the user during a session, and can then
pass all this information to the third party along with any
identifying information (names, credit card numbers, addresses)
obtained by the site. If a third party cooperates with multiple
sites to obtain such information, a profile can still be
created.
However, user tracking is to some extent possible even with no
cooperation from the user agent whatsoever, for instance by using
session identifiers in URLs, a technique already commonly used for
innocuous purposes but easily repurposed for user tracking (even
retroactively). This information can then be shared with other
sites, using visitors' IP addresses and other user-specific
data (e.g. user-agent headers and configuration settings) to combine
separate sessions into coherent user profiles.
8.2.
Cookie resurrection
If the user interface for persistent storage presents data in the
persistent storage features described in this specification separately
from data in HTTP session cookies, then users are likely to delete
data in one and not the other. This would allow sites to use the two
features as redundant backup for each other, defeating a user’s
attempts to protect his privacy.
8.3.
Sensitivity of data
User agents should treat persistently stored data as potentially
sensitive; it is quite possible for e-mails, calendar appointments,
health records, or other confidential documents to be stored in this
mechanism.
To this end, user agents should ensure that when deleting data,
it is promptly deleted from the underlying storage.
9.
Security considerations
9.1.
DNS spoofing attacks
Because of the potential for DNS spoofing attacks, one cannot
guarantee that a host claiming to be in a certain domain really is
from that domain. To mitigate this, pages can use TLS. Pages using TLS
can be sure that only pages using TLS that have certificates
identifying them as being from the same domain can access their
databases.
9.2.
Cross-directory attacks
Different authors sharing one host name, for example users hosting
content on
geocities.com
, all share one set of databases.
There is no feature to restrict the access by pathname. Authors on
shared hosts are therefore recommended to avoid using these features,
as it would be trivial for other authors to read the data and
overwrite it.
NOTE:
Even if a path-restriction feature was made available, the usual DOM
scripting security model would make it trivial to bypass this
protection and access the data from any path.
9.3.
Implementation risks
The two primary risks when implementing these persistent storage
features are letting hostile sites read information from other
domains, and letting hostile sites write information that is then read
from other domains.
Letting third-party sites read data that is not supposed to be read
from their domain causes
information leakage
, For example, a
user’s shopping wish list on one domain could be used by another
domain for targeted advertising; or a user’s work-in-progress
confidential documents stored by a word-processing site could be
examined by the site of a competing company.
Letting third-party sites write data to the persistent storage of
other domains can result in
information spoofing
, which is
equally dangerous. For example, a hostile site could add records to a
user’s wish list; or a hostile site could set a user’s session
identifier to a known ID that the hostile site can then use to track
the user’s actions on the victim site.
Thus, strictly following the storage key partitioning model described in
this specification is important for user security.
If host names or database names are used to construct paths for
persistence to a file system they must be appropriately escaped to
prevent an adversary from accessing information from other
storage keys
using relative paths such as "
../
".
9.4.
Persistence risks
Practical implementations will persist data to a non-volatile storage
medium. Data will be serialized when stored and deserialized when
retrieved, although the details of the serialization format will be
user-agent specific. User agents are likely to change their
serialization format over time. For example, the format may be updated
to handle new data types, or to improve performance. To satisfy the
operational requirements of this specification, implementations must
therefore handle older serialization formats in some way. Improper
handling of older data can result in security issues. In addition to
basic serialization concerns, serialized data could encode assumptions
which are not valid in newer versions of the user agent.
A practical example of this is the
RegExp
type. The
StructuredSerializeForStorage
operation allows serializing
RegExp
objects. A typical user agent will compile a regular expression into
native machine instructions, with assumptions about how the input data
is passed and results returned. If this internal state was serialized
as part of the data stored to the database, various problems could
arise when the internal representation was later deserialized. For
example, the means by which data was passed into the code could have
changed. Security bugs in the compiler output could have been
identified and fixed in updates to the user agent, but remain in the
serialized internal state.
User agents must identify and handle older data appropriately. One
approach is to include version identifiers in the serialization
format, and to reconstruct any internal state from script-visible
state when older data is encountered.
10.
Accessibility considerations
This section is non-normative.
The API described by this specification has limited accesibility considerations:
It does not provide for visual rendering of content, or control over color.
It does not provide features to accept user input.
It does not provide user interaction features.
It does not define document semantics.
It does not provide time-based visual media.
It does not allow time limits.
It does not directly provide content for end-users, either in textual, graphical or other or non-textual form.
It does not define a transmission protocol.
The API does allow storage of structured content. Textual content can be stored as strings. Support exists in the API for developers to store alternative non-textual content such as images or audio as
Blob
File
, or
ImageData
objects. Developers producing dynamic content applications using the API should ensure that the content is accessible to users with a variety of technologies and needs.
While the API itself does not define a specific mechanism for it, storage of structured content also allows developers to store internationalized content, using different records or structure within records to hold language alternatives.
The API does not define or require any a user agent to generate a user interface to enable interaction with the API. User agents may optionally provide user interface elements to support the API. Examples include prompts to users when additional storage quota is required, functionality to observe storage used by particular web sites, or tools specific to the API’s storage such as inspecting, modifying, or deleting records. Any such user interface elements must be designed with accessibility tools in mind. For example, a user interface presenting the fraction of storage quota used in graphical form must also provide the same data to tools such as screen readers.
11.
Revision history
This section is non-normative.
The following is an informative summary of the changes since the last
publication of this specification. A complete revision history can be
found
here
For the revision history of the first edition, see
that document’s Revision History
For the revision history of the second edition, see
that document’s Revision History
12.
Acknowledgements
This section is non-normative.
Special thanks to Nikunj Mehta, the original author of the first
edition, and Jonas Sicking, Eliot Graff, Andrei Popescu, and Jeremy
Orlow, additional editors of the first edition.
Garret Swart was extremely influential in the design of this specification.
Thanks to Tab Atkins, Jr. for creating and maintaining
Bikeshed
, the
specification authoring tool used to create this document, and
for his general authoring advice.
Special thanks to
Abhishek Shanthkumar,
Adam Klein,
Addison Phillips,
Adrienne Walker,
Alec Flett,
Andrea Marchesini,
Andreas Butler,
Andrew Sutherland,
Anne van Kesteren,
Anthony Ramine,
Ari Chivukula,
Arun Ranganathan,
Ben Dilts,
Ben Turner,
Bevis Tseng,
Boris Zbarsky,
Brett Zamir,
Chris Anderson,
Dana Florescu,
Danillo Paiva,
David Grogan,
Domenic Denicola,
Dominique Hazael-Massieux,
Evan Stade,
Glenn Maynard,
Hans Wennborg,
Isiah Meadows,
Israel Hilerio,
Jake Archibald,
Jake Drew,
Jerome Hode,
Josh Matthews,
João Eiras,
Kagami Sascha Rosylight,
Kang-Hao Lu,
Kris Zyp,
Kristof Degrave,
Kyaw Tun,
Kyle Huey,
Laxminarayan G Kamath A,
Maciej Stachowiak,
Marcos Cáceres,
Margo Seltzer,
Marijn Kruisselbrink,
Ms2ger,
Odin Omdal,
Olli Pettay,
Pablo Castro,
Philip Jägenstedt,
Shawn Wilsher,
Simon Pieters,
Steffen Larssen,
Steve Becker,
Tobie Langel,
Victor Costan,
Xiaoqian Wu,
Yannic Bonenberger,
Yaron Tausky,
Yonathan Randolph,
and
Zhiqiang Zhang,
all of whose feedback and suggestions have led to improvements to this
specification.