インデックス付きデータベースAPI 3.0

W3C作業草案,

この文書の詳細
このバージョン:
https://www.w3.org/TR/2025/WD-IndexedDB-3-20250813/
最新版:
https://www.w3.org/TR/IndexedDB/
編集者ドラフト:
https://w3c.github.io/IndexedDB/
以前のバージョン:
履歴:
https://www.w3.org/standards/history/IndexedDB-3/
テストスイート:
https://github.com/web-platform-tests/wpt/tree/master/IndexedDB
フィードバック:
GitHub
編集者:
(Microsoft)
以前の編集者:
Ali Alabbas (元Microsoft)
Joshua Bell (元Google)

概要

本書は、単純な値や階層的なオブジェクトを保持するレコードのデータベースのAPIを定義します。各レコードはキーと値で構成されます。さらに、データベースは保存されているレコードに対してインデックスを管理します。アプリケーション開発者はAPIを直接利用して、キーまたはインデックスを使ってレコードを検索できます。クエリ言語はこのAPIの上にレイヤー化することができます。インデックス付きデータベースは永続的なB木データ構造を用いて実装可能です。

この文書のステータス

このセクションは、本書の公開時点における文書のステータスを説明します。現行のW3C出版物や本技術文書の最新版は、W3C標準および草案インデックスで確認できます。

本書は Web Applications Working Group によって 作業草案として、勧告ルートを用いて公開されました。 作業草案として公開されていても、W3Cおよびその会員による承認を意味するものではありません。

本書はドラフト文書であり、今後随時更新、差し替え、または他の文書によって廃止される可能性があります。 進行中の作業以外のものとして本書を引用することは適切ではありません。

本書は、W3C特許ポリシーの下で活動するグループによって作成されました。W3Cは、グループの成果物に関連してなされた特許開示の公開リストを管理しています。そのページには特許の開示方法についても記載されています。個人が本当に特許があり、必須クレームを含むと考える場合、その情報をW3C特許ポリシー第6節に従って開示する必要があります。

本書は 2023年11月3日 W3Cプロセス文書に準拠しています。

これは Indexed Database API の第三版です。 第一版、 単に「Indexed Database API」と題され、 2015年1月8日にW3C勧告となりました。 第二版、 「Indexed Database API 2.0」と題され、 2018年1月30日にW3C勧告となりました。

Indexed Database API 3.0はIndexed Database API 2.0を置き換えることを目的としています。

1. はじめに

ユーザーエージェントは、Webアプリケーションのオフラインデータ要件を満たすために、大量のオブジェクトをローカルに保存する必要があります。[WEBSTORAGE] は、キーとその値のペアを保存するのに役立ちます。 しかし、キーの順序付き取得や値の効率的な検索、キーに対する重複値の保存などは提供しません。

この仕様は、高度なキー・値データ管理を行う具体的なAPIを提供します。これは多くの高度なクエリプロセッサの中心的機能です。トランザクション型データベースを使用してキーとそれに対応する値(キーごとに1つ以上)を保存し、キーを決定的な順序で巡回する手段を提供します。これはしばしば、非常に大量のデータレコードの挿入・削除・順序付き巡回に効率的とされる永続的なB-treeデータ構造を用いて実装されます。

次の例は、APIを使って"library"データベースへアクセスするものです。"books"オブジェクトストアには"isbn"プロパティを主キーとして書籍レコードが保存されています。

書籍レコードには"title"プロパティがあります。この例では書籍タイトルが一意であることを求めます。コードは"by_title"という名前のインデックスをunique オプション付きで作成し、タイトルで書籍検索を可能にし、重複タイトルの追加を防ぎます。

書籍レコードには"author"プロパティもあり、こちらは一意である必要はありません。コードは"by_author"というインデックスも作成し、このプロパティで検索できるようにします。

コードはまずデータベースへの接続を開きます。upgradeneeded イベントハンドラーで必要に応じてオブジェクトストアとインデックスを作成します。success イベントハンドラーは後の例で使うために開いた接続を保存します。

const request = indexedDB.open("library");
let db;

request.onupgradeneeded = function() {
  // データベースが存在しない場合は、オブジェクトストアとインデックスを作成します。
  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");

  // 初期データで埋める。
  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;
};

次の例はトランザクションを使ってデータベースにデータを追加します。

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() {
  // すべてのリクエストが成功し、トランザクションがコミットされました。
};

次の例はインデックスを使ってタイトルで単一の書籍を検索します。

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) {
    // 該当するレコードが見つかりました。
    report(matching.isbn, matching.title, matching.author);
  } else {
    // 該当するレコードがありませんでした。
    report(null);
  }
};

次の例はインデックスとカーソルを使って著者で全ての書籍を検索します。

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) {
    // 各該当レコードごとに呼び出されます。
    report(cursor.value.isbn, cursor.value.title, cursor.value.author);
    cursor.continue();
  } else {
    // 該当レコードがもうありません。
    report(null);
  }
};

次の例はリクエストが失敗した場合のエラー処理方法の一例です。

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) {
  // "by_title"インデックスの一意制約が失敗しました。
  report(request.error);
  // event.preventDefault()を呼び出せば、トランザクションの自動中止を防げます。
};
tx.onabort = function() {
  // 失敗したリクエストによりトランザクションは自動で中止されます。
  report(tx.error);
};

データベース接続は不要になったら閉じることができます。

db.close();

将来、データベースに他のオブジェクトストアやインデックスが追加されているかもしれません。次の例は、古いバージョンからの移行方法の一例です。

const request = indexedDB.open("library", 3); // バージョン3を要求。
let db;

request.onupgradeneeded = function(event) {
  const db = request.result;
  if (event.oldVersion < 1) {
    // バージョン1はデータベースの最初のバージョン。
    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 < 2) {
    // バージョン2では書籍の年による新しいインデックスが導入されます。
    const bookStore = request.transaction.objectStore("books");
    const yearIndex = bookStore.createIndex("by_year", "year");
  }
  if (event.oldVersion < 3) {
    // バージョン3では雑誌用の新しいオブジェクトストアと2つのインデックスが追加されます。
    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は3になります。
};
ひとつのデータベースは複数のクライアント(ページやワーカー)によって同時に使われることができます。トランザクションにより、読み書きが衝突しないよう制御されます。 新しいクライアントがデータベースのアップグレード(upgradeneeded イベント)を行いたい場合、他のクライアントがデータベースの現在のバージョンへの接続をすべて閉じるまで、それを行うことはできません。

新しいクライアントによるアップグレードの妨げを防ぐため、クライアントは versionchange イベントを監視できます。これは他のクライアントがデータベースのアップグレードを求めているときに発火します。これに対応して、このクライアントの接続を閉じるような処理を行い、アップグレードを許可します。

このための一つの方法はページをリロードすることです:

db.onversionchange = function() {
  // まず、未保存データを保存:
  saveUnsavedData().then(function() {
    // ドキュメントがアクティブでない場合は、ユーザー操作なしでページをリロードしてもよいでしょう。
    if (!document.hasFocus()) {
      location.reload();
      // リロードによりデータベースが閉じられ、新しいJavaScriptおよびデータベース定義も読み込まれます。
    } else {
      // ドキュメントがフォーカスされている場合、ページのリロードは強制的すぎるかもしれません。
      // ユーザーに手動でリロードしてもらうよう促すこともできます:
      displayMessage("最新バージョンのため、このページをリロードしてください。");
    }
  });
};

function saveUnsavedData() {
  // 実装方法はアプリによります。
}

function displayMessage() {
  // ユーザーに非モーダルメッセージを表示します。
}

もう一つの方法は接続close() メソッドを呼び出すことです。ただし、これを行う場合はアプリがその状態を認識している必要があり、以降のデータベースアクセスは失敗します。

db.onversionchange = function() {
  saveUnsavedData().then(function() {
    db.close();
    stopUsingTheDatabase();
  });
};

function stopUsingTheDatabase() {
  // アプリがデータベースを使用しない状態にします。
}

新しいクライアント(アップグレードを試みている側)は、他のクライアントがアップグレードを妨げているかをblocked イベントで検出できます。blocked イベントは、他のクライアントがversionchange を受け取った後もデータベースへの接続を保持している場合に発火します。

const request = indexedDB.open("library", 4); // バージョン4を要求。
let blockedTimeout;

request.onblocked = function() {
  // 他のクライアントが非同期でデータを保存できるよう時間を与えます。
  blockedTimeout = setTimeout(function() {
    displayMessage("アップグレードがブロックされています - このサイトを表示している他のタブを閉じてください。");
  }, 1000);
};

request.onupgradeneeded = function(event) {
  clearTimeout(blockedTimeout);
  hideMessage();
  // ...
};

function hideMessage() {
  // 以前表示したメッセージを非表示にします。
}

上記のメッセージは、他のクライアントがデータベースから切断しなかった場合のみユーザーに表示されます。理想的にはユーザーがこのメッセージを見ることはありません。

2. 構成要素

name(名前)とは、string に相当し、DOMString と同じです。 つまり、任意の長さの16ビットコードユニットの並びであり、空文字列も含みます。name(名前)は常に 16ビットコードユニットの不透明な並びとして比較されます。

注意: そのため、name の比較は大文字小文字の違いや、 正規化形式の差異、制御文字の有無、その他Unicodeテキストの細かな違いにも影響されます。[Charmod-Norm]

実装が任意の文字列をサポートしない記憶装置を使う場合は、エスケープ機構などを使って指定された name を保存可能な文字列へマッピングできます。

ソート済みnameリストを作成するには、 list names を使い、以下の手順を実行します:

  1. sortednames昇順でソートしたものを格納します。ソートには code unit less than アルゴリズムを使います。

  2. sorted に対応する新しい DOMStringList を返します。

詳細 これは sort() メソッドと一致します。 ArrayString に対して、各文字列の16ビットコードユニットを比較し、高速かつ一貫性のある決定的なソート順を生成します。結果のリストは特定のアルファベット順や辞書順とは一致しません。サロゲートペアで表されるコードポイントでは特にそうです。

2.1. データベース

storage key は関連する データベース の集合を持ちます。 データベース は0個以上の オブジェクトストア を持ち、 データベースに保存されたデータを保持します。

データベースは、特定の name(名前)を持ち、個々の storage key 内で識別されます。name は name であり、データベースの寿命中は一定です。

データベースversion(バージョン)を持ちます。データベースが初めて作成されたときは、 version は0(ゼロ)です。

注意:データベース は同時に1つのバージョンのみ持ちます。 データベースが複数バージョンで同時に存在することはありません。 バージョンを変更する唯一の方法は、アップグレードトランザクションを使うことです。

データベースは最大1つの関連 upgrade transaction(アップグレードトランザクション)を持ちます。 これは null か アップグレードトランザクション のいずれかで、初期値は null です。

2.1.1. データベース接続

スクリプトは データベース と直接やり取りしません。 スクリプトは connection(接続)を介して間接的にアクセスします。 connection オブジェクトは、対応する データベースのオブジェクト操作に使えます。 また、データベースに対する トランザクションを 取得する唯一の手段です。

データベースを開くことで connection が作成されます。 1つの データベース に複数の connection が同時に存在する場合もあります。

connection は、 storage key のグローバルスコープから開かれた データベースのみアクセスできます。

注意: これは Documentdomain の変更によって影響されません。

connectionversion(バージョン)を持ち、 connection の作成時にセットされます。 connection の寿命中は一定ですが、 アップグレードが中止された場合は データベースの前のバージョンに変更されます。connection が閉じられた後は version は変化しません。

各接続は close pending flag(閉じ待ちフラグ)を持ち、初期値は false です。

connection が作成された直後は opened(開かれた)状態です。接続は複数の方法で closed(閉じられた)状態になりえます。 connection が作成された実行コンテキストが 破棄された場合(例えばユーザーがページから離れた場合)、接続は閉じられます。データベース接続を閉じる手順を使って明示的に閉じることもできます。 接続が閉じられると、その close pending flag はまだ設定されていなければ必ず true になります。

connection は、例外的な状況下で ユーザーエージェントによって閉じられる場合があります。例えばファイルシステムへのアクセス喪失、権限変更、storage key のストレージ消去などです。この場合、ユーザーエージェントは データベース接続を閉じる手順を connection に対して forced flag を true にして実行します。

connectionobject store set(オブジェクトストア集合)を持ち、 connection の作成時に関連付けられた データベースオブジェクトストア集合で初期化されます。 アップグレードトランザクションlive(生存中)の場合のみ内容が変化し得ます。

connectionget the parent アルゴリズムは null を返します。

イベント型 versionchange は、 オープン中の connection に対して、 データベースのアップグレードや削除が試みられた場合に発火します。 connection に アップグレードや削除を進めるために閉じる機会を与えます。

イベント型 close は、 connection が異常終了により 閉じられた場合に発火します。

2.2. オブジェクトストア

オブジェクトストアは、 データベース内でデータを保存する主要な保存機構です。

各データベースはオブジェクトストアの集合を持ちます。 オブジェクトストアの集合は変更できますが、 アップグレードトランザクション (すなわちupgradeneeded イベントへの応答時)のみ可能です。 新しいデータベースが作成された時点では、オブジェクトストアは含まれていません。

オブジェクトストアレコードのリストを持ちます。 これはオブジェクトストアに格納されたデータです。 各レコードキーから構成されます。リストはキーに従い 昇順でソートされます。 1つのオブジェクトストア内で同じキーを持つ複数のレコードが存在することはありません。

オブジェクトストア名前を持ち、これはnameです。 ある時点で、その名前は所属するデータベース内で一意です。

オブジェクトストアは 任意でキーパスを持ちます。 キーパスがある場合はインラインキーを使うと言い、 ない場合はアウトオブラインキーを使うと言います。

オブジェクトストアは 任意でキー生成器を持ちます。

オブジェクトストアは、レコードキーを以下の3つのいずれかの方法で導出できます:

  1. キー生成器。 キー生成器はキーが必要なたびに単調増加する数値を生成します。

  2. キーパスでキーを導出できます。

  3. をオブジェクトストアに保存する際、キーを明示的に指定することもできます。

2.2.1. オブジェクトストアハンドル

スクリプトはオブジェクトストアと直接やり取りしません。 代わりに、トランザクション内で間接的に オブジェクトストアハンドル を介してアクセスします。

オブジェクトストアハンドルは 関連するオブジェクトストアトランザクションを持ちます。 複数のハンドルが異なるトランザクションで 同じオブジェクトストアに紐づくことは可能ですが、 特定のトランザクション内で 1つのオブジェクトストアに 紐づくハンドルは1つだけです。

オブジェクトストアハンドルインデックス集合を持ちます。 これは、ハンドル作成時に関連するオブジェクトストアを参照する インデックスの集合で初期化されます。 アップグレードトランザクションliveの場合のみ内容が変化し得ます。

オブジェクトストアハンドル名前を持ちます。 これはハンドル作成時に関連するオブジェクトストアの名前で初期化されます。 名前はアップグレードトランザクションliveの場合のみ変更されることがあります。

2.3.

各レコードにはが関連付けられています。ユーザーエージェントは あらゆるシリアライズ可能オブジェクトをサポートしなければなりません。これには、 String のプリミティブ値やDate オブジェクト、ObjectArray インスタンス、File オブジェクト、Blob オブジェクト、ImageData オブジェクトなどが含まれます。レコードのは参照ではなく値として保存・取得されるため、値を後から変更してもデータベース内のレコードには影響しません。

レコードのは、Record型で、 StructuredSerializeForStorage操作の出力です。

2.4. キー

インデックス付きデータベースに保存されたレコードを効率的に取得するため、各レコードはその キーに従って整理されます。

キーには関連するがあり、 以下のいずれかです: number(数値)、 date(日付)、 string(文字列)、 binary(バイナリ)、 array(配列)。

キーはさらに、関連するを持ちます。 これは以下のいずれかです: numberまたはdateの場合は unrestricted doublestringの場合はDOMStringbinaryの場合はバイト列arrayの場合は他のキーリストです。

ECMAScript [ECMA-262]値は、 値をキーに変換する手順によって キーに変換できます。

注意: 次のECMAScript型は有効なキーです:

その他のECMAScript値をキーに変換しようとすると失敗します。

配列キーは、キーのうち arrayのものです。 サブキー配列キー要素です。 配列キーになります。

2つのキーを比較するには、abに対し以下の手順を行います:

  1. taaとする。

  2. tbbとする。

  3. もしtatbが異なれば、以下を実行:

    1. taarrayなら1を返す。

    2. tbarrayなら-1を返す。

    3. tabinaryなら1を返す。

    4. tbbinaryなら-1を返す。

    5. tastringなら1を返す。

    6. tbstringなら-1を返す。

    7. tadateなら1を返す。

    8. Asserttbdateである。

    9. -1を返す。

  4. vaaとする。

  5. vbbとする。

  6. taに応じて分岐:

    number
    date
    1. もしvavbより大きければ1を返す。

    2. もしvavbより小さければ-1を返す。

    3. 0を返す。

    string
    1. もしvavbよりコードユニット順で小さければ-1を返す。

    2. もしvbvaよりコードユニット順で小さければ1を返す。

    3. 0を返す。

    binary
    1. もしvavbよりバイト順で小さければ-1を返す。

    2. もしvbvaよりバイト順で小さければ1を返す。

    3. 0を返す。

    array
    1. lengthvaサイズvbサイズの小さい方とする。

    2. iに0をセット。

    3. ilength未満の間、以下を繰り返す:

      1. cを再帰的に2つのキーを比較するva[i]とvb[i]を比較した結果とする。

      2. cが0でなければcを返す。

      3. iを1増やす。

    4. vaサイズvbサイズより大きければ1を返す。

    5. vaサイズvbサイズより小さければ-1を返す。

    6. 0を返す。

キーaより大きいのは、 2つのキーを比較するabに対して実行した結果が1の場合です。

キーaより小さいのは、 2つのキーを比較するabに対して実行した結果が-1の場合です。

キーa等しいのは、 2つのキーを比較するabに対して実行した結果が0の場合です。

注意: 上記規則の結果、負の無限大はキーの最小値です。 numberキーはdateキーより小さく、 dateキーはstringキーより小さく、 stringキーはbinaryキーより小さく、 binaryキーはarrayキーより小さいです。 キー値の最大値は存在しません。 これは、いかなる候補となる最大キーの配列に別のキーを続ければさらに大きくなるためです。

注意: binaryキーの要素は符号なしバイト(0~255)として比較されます。符号付きbyte (-128~127)とは異なります。

2.5. キーパス

キーパスは、文字列または文字列のリストであり、 キーから抽出する方法を定義します。有効なキーパスは以下のいずれかです:

注意: キーパス内に空白は許可されません。

キーパス値は、 StructuredSerializeForStorageによって 明示的にコピーされたプロパティおよび以下の型固有プロパティからのみアクセスできます:

プロパティ
Blob size, type
File name, lastModified
Array length
String length

2.6. インデックス

時には、レコードオブジェクトストア内で キー以外の方法で取得したい場合があります。 インデックスは、 レコードオブジェクトストア内で のプロパティを使って検索できるようにします。 オブジェクトストアレコードに対してです。

インデックスは、特殊な永続的なキー・バリュー型ストレージであり、参照先オブジェクトストアを持ちます。 インデックスには、インデックスに保存されたデータを保持するレコードの一覧があります。 インデックス内のレコードは、参照先のオブジェクトストアでレコードが挿入、更新、または削除されるたびに自動的に追加・更新されます。 同じオブジェクトストアを参照するインデックスが複数存在する場合、オブジェクトストアに変更があると、それら全てのインデックスが更新されます。

インデックスのは、常にインデックスのレコード内のキーの値であり、インデックスの参照先オブジェクトストアに存在します。 キーは、参照先オブジェクトストアのからキーパスを使って導出されます。 例えば、インデックスが参照するオブジェクトストアにキーXレコードがあり、その値がAで、インデックスのキーパスA評価すると結果がYになった場合、インデックスにはキーY、値Xのレコードが含まれることになります。

例えば、インデックスの参照先オブジェクトストアに キー123、値{ name: "Alice", title: "CEO" }のレコードがあり、 インデックスのキーパスが "name"の場合、インデックスにはキー"Alice"、値123のレコードが含まれることになります。

インデックス内のレコードは参照値(referenced value)を持つと言います。 これはインデックスの参照先オブジェクトストアでキーがインデックスのレコード値と等しいレコードの値です。 先の例では、インデックス内でキーY、値Xのレコードの 参照値Aです。

先ほどの例では、インデックス内でキー"Alice"、値123のレコードの 参照値{ name: "Alice", title: "CEO" }となります。

注意: インデックス内の各レコードは、そのインデックスの参照先オブジェクトストアのレコードを1つだけ参照します。ただし、インデックス内には同じオブジェクトストアのレコードを参照する複数のレコードが存在する場合があります。また、オブジェクトストアのあるレコードを参照するインデックスレコードが1つも存在しない場合もあります。

インデックス内のレコードは、常に レコードのキーでソートされます。ただし、オブジェクトストアとは異なり、インデックスには同じキーを持つ複数のレコードが含まれることがあります。そのようなレコードはさらに、インデックスのレコードの値(つまり参照先オブジェクトストア内のレコードのキー)でソートされます。

インデックス名前name)を持ちます。 名前は常にインデックスの参照先オブジェクトストア内で一意です。

インデックス一意フラグを持ちます。trueの場合、インデックスはインデックス内の レコードが同じキーを持たないように強制します。インデックスの参照オブジェクトストアで レコードの追加や変更が行われ、その新しい値でインデックスのキー・パスを評価した結果がすでにインデックス内に存在する場合、 そのオブジェクトストアへの変更は失敗します。

インデックスmultiEntryフラグを持ちます。このフラグは、インデックスの キー・パスを評価した結果が 配列キーだった場合のインデックスの挙動に影響します。 multiEntryフラグ がfalseの場合は、キー配列キーである1つのレコードがインデックスに追加されます。trueの場合は、 サブキーごとに1つずつレコードがインデックスに追加されます。

2.6.1. インデックスハンドル

スクリプトはインデックスと直接やり取りしません。代わりに、 トランザクション内で 間接的にインデックスハンドルを介してアクセスします。

インデックスハンドルは 関連するインデックスオブジェクトストアハンドルを持ちます。 インデックスハンドルトランザクションは、関連するオブジェクトストアハンドルのトランザクションです。 複数のハンドルが異なるトランザクションで 同じインデックスに紐づくことは可能ですが、 特定のトランザクション内で 1つのインデックスに 紐づくインデックスハンドルは1つだけです。

インデックスハンドル名前を持ちます。 これはハンドル作成時に関連するインデックスの名前で初期化されます。 名前はアップグレードトランザクションliveの場合のみ変更されることがあります。

2.7. トランザクション

トランザクションデータベース内のデータ操作に使われます。 データベースの読み書きは必ずトランザクション経由で行われます。

トランザクションは アプリケーションやシステムの障害からある程度保護します。 トランザクションは複数のデータレコードを保存したり、 条件付きで一部レコードを変更したりできます。 トランザクションは 原子的かつ永続的なデータアクセス・変更操作の集合です。

すべてのトランザクションは接続経由で作成されます。これはトランザクションの接続です。

トランザクションスコープを持ちます。これは、トランザクションが操作できる 集合オブジェクトストアです。

注意: トランザクションスコープアップグレードトランザクションでない限り固定です。

2つのトランザクションは、どちらのスコープにも同じオブジェクトストアが含まれる場合 スコープが重複していると言います。

トランザクションモードを持ち、 そのトランザクションでどの操作ができるかを決めます。 モードは 作成時にセットされ、トランザクションの生存期間中は固定です。 トランザクションモードは以下のいずれかです:

"readonly"

このトランザクションはデータの読み取りのみ許可されます。変更はできません。 このタイプのトランザクションは、スコープが重複している(同じオブジェクトストアを使う)場合でも 複数同時に開始できます。 データベースが開かれた後はいつでも作成できます。

"readwrite"

このトランザクションは既存のオブジェクトストアからデータの読み取り、変更、削除が可能です。 ただし、オブジェクトストアやインデックスの追加・削除はできません。 複数の"readwrite" トランザクションは、スコープが重複している場合は同時に開始できません。 これは、トランザクションの途中で互いのデータを変更できてしまうためです。 データベースが開かれた後はいつでも作成できます。

"versionchange"

このトランザクションは既存のオブジェクトストアのデータの読み取り、変更、削除に加え、 オブジェクトストアやインデックスの新規作成・削除が可能です。 このような操作ができる唯一のタイプです。 このトランザクションは手動では作成できず、upgradeneeded イベント発火時に自動で作成されます。

トランザクション耐久性ヒントを持つことがあります。 これはコミット時にパフォーマンスか耐久性のどちらを優先するかを示します。 耐久性ヒントは以下のいずれかです:

"strict"

すべての変更が永続的記憶媒体に正常に書き込まれたことを確認した後のみ、 ユーザーエージェントはトランザクションが正常にコミットされたとみなすことができます。

"relaxed"

すべての変更がOSに書き込まれた時点で、追加の検証なしで トランザクションが正常にコミットされたとみなすことができます。

"default"

ユーザーエージェントはストレージバケットに対し デフォルトの耐久性動作を使うべきです。これは特に指定しない場合のデフォルトです。

注意: 典型的な実装では、"strict" はユーザーエージェントへのヒントとなり、complete イベント発火前にOSのI/Oバッファをフラッシュするよう促します。 これにより、OSクラッシュや電源喪失があっても変更が永続化される可能性が高まりますが、 バッファフラッシュは時間がかかり、携帯端末ではバッテリー消費も増えます。

Webアプリケーションはキャッシュや頻繁に変わる一時的データには "relaxed" を、データ損失リスク低減がパフォーマンスや電力消費への影響より重要な場合は "strict" を推奨します。 実装はアプリケーションからの耐久性ヒントとユーザー/デバイスへの影響を総合的に考慮すべきです。

トランザクションは 任意でクリーンアップイベントループを持ちます。 これはイベントループです。

トランザクションは 保留中のリクエストリストを持ちます。

トランザクションエラーを持ち、トランザクション中止された場合にセットされます。

注意: 実装者は値"null"もエラーとして扱われることに注意してください。これはabort()からセットされます。

トランザクションget the parent アルゴリズムはトランザクションの接続を返します。

読み取り専用トランザクショントランザクションモードが "readonly"です。

読み書きトランザクショントランザクションモードが "readwrite"です。

2.7.1. トランザクションのライフサイクル

トランザクション状態を持ち、次のいずれかです:

アクティブ

トランザクションが初めて作成された時や、 トランザクションに関連付けられたリクエストからイベントが発行されている間はこの状態になります。

この状態のときのみ新しいリクエストをトランザクションに対して行えます。

非アクティブ

トランザクションの作成後に制御がイベントループに戻ったときや、イベントが発行されていないときはこの状態です。

この状態のとき、トランザクションに対してリクエストを行うことはできません。

コミット中

トランザクションに関連するすべてのリクエストが完了すると、 コミットを試みるためこの状態になります。

この状態のとき、トランザクションに対してリクエストを行うことはできません。

完了

トランザクションがコミットまたは中止された後、この状態になります。

この状態のとき、トランザクションに対してリクエストを行うことはできません。

トランザクションは短命であることが期待されます。これは下記の自動コミット機能によって促進されます。

注意: 著者はトランザクションを生存状態で長時間維持することもできますが、 この利用パターンは推奨されません。ユーザー体験が悪化する可能性があります。

トランザクションライフタイムは次の通りです:

  1. トランザクションは作成時にスコープモードが設定され、 状態は最初にアクティブになります。

  2. 実装がトランザクションのスコープモードの制約を (下記参照)満たせる場合、 実装は非同期でトランザクションを開始するデータベースタスクをキューします。

    トランザクションが開始されると、 実装はトランザクションに対して行われたリクエストの実行を開始できます。リクエストは トランザクションに対して行われた順に実行し、結果も同じ順で返さなければなりません。 ただし、異なるトランザクション間のリクエスト結果の順序は保証されません。

    注意: トランザクションのモードは 異なるトランザクションに対して行われたリクエストがどの順番で実行されても、 データベースに保存される結果に影響しないことを保証します。

  3. トランザクションに関連する各リクエスト処理されると、 success またはerrorイベントが発火します。 イベントをディスパッチしている間は トランザクションの状態アクティブとなり、 追加のリクエストが可能です。イベントのディスパッチが完了すると、 状態は再び非アクティブとなります。

  4. トランザクションは完了する前なら、アクティブでなくても、まだ開始されていなくても いつでも中止できます。

    abort() を明示的に呼ぶことで 中止が開始されます。 スクリプトで処理されないリクエストの失敗でも中止が開始されます。

    トランザクションが中止された場合、実装はそのトランザクション中にデータベースに加えた変更(オブジェクトストア内容の変更、オブジェクトストア・インデックスの追加・削除)をすべて元に戻さなければなりません。

  5. 実装は、トランザクションに対して行われたすべてのリクエストが完了し、 その返却結果が処理され、新しいリクエストが行われておらず、中止されていない場合、 非アクティブなトランザクションを コミットしようとしなければなりません。

    commit() の明示的呼び出しは、リクエスト結果がスクリプトで処理されるのを待たずに コミットを開始します。

    コミット時、トランザクションの状態コミット中になります。 実装はトランザクションで行われたすべての変更をデータベースに原子的に書き込まなければなりません。 すべての変更が書き込まれるか、エラー(例えばディスク書き込みエラー)が発生した場合は変更を一切書き込まず トランザクションの中止手順が実行されます。

  6. トランザクションがコミットまたは 中止されると、 状態は完了になります。

実装は、トランザクションがアクティブな間は リクエスト置くことを許可しなければなりません。 これはトランザクションがまだ開始されていなくても同様です。 開始されるまではリクエストは実行されませんが、実装はリクエストとその順序を記録しておく必要があります。

トランザクション生存状態は作成時から状態が完了にセットされるまでです。

Indexed Database トランザクションのクリーンアップ方法は以下の通りです。 何らかのトランザクションがクリーンアップされた場合は true、されなければ false を返します。

  1. 現在のイベントループクリーンアップイベントループが一致する トランザクションがなければ false を返す。

  2. 現在のイベントループクリーンアップイベントループが一致する 各トランザクション transactionに対して:

    1. transaction状態非アクティブにセットする。

    2. transactionクリーンアップイベントループをクリアする。

  3. true を返す。

注意: これらの手順は[HTML]によって呼び出されます。 スクリプトからtransaction() を呼び出して作成されたトランザクションが 呼び出し元タスクの完了後に非アクティブ化されることを保証します。 この手順は各トランザクションにつき最大1回だけ実行されます。

completeのイベントは、 正常にコミットされたトランザクションに対して発火します。

abortのイベントは、 中止された トランザクションに対して発火します。

2.7.2. トランザクションのスケジューリング

以下の制約により、トランザクション開始できるタイミングが決まります:

実装は追加の制約を課しても構いません。例えば、実装は開始される 非重複スコープの 読み書きトランザクションを並列で処理することを要求されませんし、 開始できるトランザクション数に上限を課しても構いません。

注意: これらの制約から次のことが導かれます:

2.7.3. アップグレードトランザクション

アップグレードトランザクションは、 トランザクションで、 モードが "versionchange"です。

アップグレードトランザクションは、 接続データベースに開いたとき、 現在のバージョンより 大きいバージョンが 指定された場合、データベースのアップグレード手順で 自動作成されます。このトランザクションは、 upgradeneeded イベントハンドラ内でアクティブになります。

注意: アップグレードトランザクションにより、 オブジェクトストアインデックスの作成・名称変更・削除が データベース内で可能となります。

アップグレードトランザクションは排他的です。 データベース接続のオープン手順は、 アップグレードトランザクションが生存しているとき データベースへの接続が1つだけオープンになるよう保証します。 upgradeneeded イベントは発火されず、 アップグレードトランザクションは開始されません。 他の接続が同じデータベースに オープンされている限りです。 これにより、すべての従来のトランザクションが完了していることが保証されます。

アップグレードトランザクション生存している間は、 同じデータベースへの追加の接続は遅延されます。 また、同じ接続transaction() を呼んで追加のトランザクションを開始しようとすると例外が発生します。 これにより、他のトランザクションが同時に生存することはなく、 アップグレードトランザクション生存している間は、 新たなトランザクションが同じデータベースに対してキューされることもありません。

さらに、アップグレードトランザクションが完了した後は、 データベース内の オブジェクトストアインデックスの集合は、 以降すべての接続トランザクションの寿命中一定となります。

2.8. リクエスト

各非同期操作は、データベース上でリクエストを使って行われます。各リクエストは1つの操作を表します。

リクエストには、最初は false に設定されるprocessed flagが存在します。 このフラグは、リクエストに関連する操作が実行されたとき true に設定されます。

リクエストは、processed flagが true の場合、処理済みとみなされます。

リクエストには、最初は false に設定されるdone flagが存在します。 このフラグは、リクエストに関連する操作の結果が利用可能になったとき true に設定されます。

リクエストにはsourceオブジェクトがあります。

リクエストにはresulterrorが存在しますが、どちらもdone flagが true になるまではアクセスできません。

リクエストには、最初は null に設定されるtransactionがあります。 これは、placedされ、transactionに対して リクエストを非同期で実行する手順が使用された場合に設定されます。

リクエストが作成されると、新しいリクエストが返され、done flagは false です。リクエストが正常に完了すると、 done flagが true になり、 resultがそのリクエストの結果に設定され、 successというタイプのイベントが リクエストに対して発火されます。

操作の実行中にエラーが発生した場合、リクエストのdone flagが true になり、 リクエストのerrorがエラーに設定され、errorというタイプのイベントがリクエストに対して発火されます。

リクエストget the parent アルゴリズムはリクエストの transactionを返します。

注記: リクエストは通常再利用されませんが、例外があります。カーソルを反復する場合、 反復の成功はカーソルを開くために使用された同じリクエストオブジェクトで報告されます。 また、アップグレードトランザクションが必要な場合、 open requestは、 upgradeneededイベントと open操作自体の最終結果の両方に使用されます。場合によってはリクエストのdone flagが false になり、再び true になり、resultが変更されたり、 errorが設定されることもあります。

2.8.1. オープンリクエスト

open requestは、 リクエストの特別な種類であり、 コネクションのオープンや データベースの削除時に使用されます。 successerrorイベントに加え、 進行状況を示すために、blockedおよびupgradeneededイベントが open requestに発火される場合があります。

sourceopen requestの場合、常に null です。

transactionopen requestの場合、 upgradeneededイベントが発火されない限り null です。

open requestget the parentアルゴリズムは null を返します。

2.8.2. 接続キュー

open requestは、 接続キューで処理されます。 キューには、open requestが、 storage keyおよびnameごとに格納されます。キューに追加された 接続キューは順番に処理され、 各リクエストが完了してから次のリクエストが処理されます。 open requestは他の接続によってブロックされる場合があり、 それらの接続が閉じられるまで リクエストが完了せず、後続リクエストの処理も進みません。

注意: 接続キューは、 タスクキューイベントループに紐づく)とは異なり、 リクエストは特定の閲覧コンテキスト外で処理されます。完了した open requestへのイベント配送は、 リクエストが行われたコンテキストのタスクキュー およびイベントループ経由で行われます。

2.9. キー範囲

オブジェクトストアインデックスからレコードを取得する際は、 キーまたはキー範囲を使います。 キー範囲は、 キーとして利用されるデータ型上の連続区間です。

キー範囲には、関連する下限(nullまたは キー)があります。

キー範囲には、関連する上限(nullまたは キー)があります。

キー範囲には、関連する下端開放フラグがあります。 明示されない限りfalseです。

キー範囲には、関連する上端開放フラグがあります。 明示されない限りfalseです。

キー範囲は、 下限上限等しい場合もあります。 キー範囲は、 下限上限より 大きい場合は許されません。

キー範囲keyのみを含む場合、 下限上限が 両方ともkeyと等しいです。

keyキー範囲に含まれる(in a key range)rangeであるとは、 以下の2条件を満たす場合です:

注意:

無限キー範囲(unbounded key range)は、 キー範囲下限上限が 両方ともnullです。すべてのキー無限キー範囲に含まれます。

valueと省略可能なnull disallowed flagを使い、 値をキー範囲に変換する手順は以下の通りです:

  1. valueキー範囲である場合、valueを返す。

  2. valueがundefinedまたはnullの場合、null disallowed flagがtrueなら 例外を投げる。 "DataError" DOMException を投げる。そうでなければ無限キー範囲を返す。

  3. keyを、値をキーに変換するの結果としてvalueで求める。例外は再スローする。

  4. keyが「不正な値」または「不正な型」の場合、 例外を投げる。 "DataError" DOMExceptionを投げる。

  5. キー範囲keyのみを含むものを返す。

潜在的に有効なキー範囲とは、 ECMAScript値で、キー範囲に変換可能な型を持つものです。 実際に変換が成功するか(値をキー範囲に変換する手順で例外が発生するか)は問いません。

注意: 例えば、切り離されたBufferSource潜在的に有効なキー範囲ですが、 値をキー範囲に変換する手順で使うと例外が発生します。

value潜在的に有効なキー範囲であるか判定するには、以下の手順を実行します:

  1. もしvalueキー範囲ならtrueを返す。

  2. keyvalue値をキーに変換する手順の結果とする。

  3. もしkeyが"invalid type"ならfalseを返す。

  4. それ以外はtrueを返す。

注意: getAll()getAllKeys() メソッドは第一引数に潜在的に有効なキー範囲を使うか判定します。 引数が潜在的に有効なキー範囲なら、 getAll()getAllKeys() はその引数で値をキー範囲に変換する手順を実行します。 そうでなければIDBGetAllOptions を第一引数に使います。

getAll()getAllKeys() は、DateArrayArrayBuffer を第一引数に与え、値をキーに変換する 手順で"invalid value"となった場合は例外を投げます。例えば、NaNな Date を第一引数にしてgetAll() を呼ぶと、デフォルト値の IDBGetAllOptions 辞書ではなく例外となります。

2.10. カーソル

カーソルは、 インデックスまたは オブジェクトストアの レコード範囲を特定の方向に反復するために使われます。

カーソルソースハンドルを持ち、 これはカーソルを開いたインデックスハンドルまたは オブジェクトストアハンドルです。

カーソルトランザクションを持ち、 これはカーソルのソースハンドルから得られる トランザクションです。

カーソル範囲を持ち、 これはインデックスまたは オブジェクトストアの範囲です。

カーソルソースを持ち、 これはカーソルのソースハンドルから得られる インデックスまたは オブジェクトストアです。 カーソルのソースは カーソルが反復しているレコードがどの インデックスまたは オブジェクトストアに紐付くかを示します。 ソースハンドルがインデックスハンドルなら、 ソースインデックスハンドルが紐付くインデックスです。 そうでなければ、カーソルのソースオブジェクトストアハンドルが紐付くオブジェクトストアです。

カーソルにはdirection(方向)があり、 イテレーション時に レコードキーの 単調に増加または減少する順序で移動するかどうか、 インデックスをイテレートする際に重複した値をスキップするかどうかを決定します。 カーソルの方向は、カーソルの初期位置が ソースの先頭か末尾かも決定します。 カーソルのdirectionは、 以下のいずれかです。

"next"

この方向の場合、カーソルはソースの先頭で開かれます。反復時、カーソルは重複も含め キーの単調増加順で全レコードを返します。

"nextunique"

この方向の場合、カーソルはソースの先頭で開かれます。反復時、同じキーのレコードは返さず、 それ以外はキーの単調増加順で全レコードを返します。重複値があるキーは最初のレコードのみ返されます。 ソースがオブジェクトストアまたは インデックスuniqueフラグがtrueの場合、 この方向は"next"とまったく同じ挙動になります。

"prev"

この方向の場合、カーソルはソースの末尾で開かれます。反復時、カーソルは重複も含め キーの単調減少順で全レコードを返します。

"prevunique"

この方向の場合、カーソルはソースの末尾で開かれます。反復時、同じキーのレコードは返さず それ以外はキーの単調減少順で全レコードを返します。重複値があるキーは最初のレコードのみ返されます。 ソースがオブジェクトストアまたは インデックスuniqueフラグがtrueの場合、 この方向は"prev"とまったく同じ挙動になります。

カーソルには、その範囲内で位置があります。 カーソルがイテレートしているレコードの一覧が、カーソルの範囲全体を イテレートし終える前に変更される可能性があります。 これに対応するため、カーソルはindexとしてではなく、直前に返されたレコードのキーとして 位置を保持します。 順方向にイテレートするカーソルの場合、次にカーソルが次のレコードへのイテレーションを要求されたとき、直前に返されたものより キーより大きい中で 最も小さいキーのレコードを返します。逆方向にイテレートするカーソルの場合は逆で、 直前に返されたものよりキーより小さい中で 最も大きいキーのレコードを返します。

インデックス反復の場合は、同じキーの複数レコードが値でソートされるため、やや複雑になります。 インデックス反復時にはカーソルは オブジェクトストア位置も持ち、 これはインデックス内で直前に見つかったレコードを示します。 位置オブジェクトストア位置の両方が 次のレコード検索に使われます。

カーソルキーを持ち、 これは直前に反復されたレコードキーです。

カーソルgot valueフラグを持ちます。 falseの場合、カーソルは次の値を読み込み中か、範囲の末尾に到達しています。 trueの場合は、カーソルが値を保持中で次に反復できる状態です。

カーソルのソースオブジェクトストアの場合、 カーソルの有効オブジェクトストアはそのオブジェクトストアであり、 有効キーはカーソルの 位置です。 ソースがインデックスの場合、 有効オブジェクトストアはそのインデックスの参照先オブジェクトストアで、 有効キーはカーソルのオブジェクトストア位置です。

カーソルリクエストを持ち、 これはカーソルを開くために使ったリクエストです。

カーソルkey onlyフラグも持ち、 API経由でカーソルのが公開されるかどうかを示します。

2.11. キー・ジェネレーター

オブジェクトストアが作成される際、 キー・ジェネレーターを使用するよう指定することができます。 キー・ジェネレーターは、オブジェクトストアにレコードが挿入される際に、他に指定されていなければキーを生成するために使われます。

キー・ジェネレーターには現在の数値があります。 現在の数値は常に1以上253(9007199254740992)+ 1以下の正の整数です。 キー・ジェネレーター現在の数値の初期値は1で、関連するオブジェクトストアが作成されたときに設定されます。 現在の数値はキーが生成されるごとに増加し、明示的なキーの使用によって特定の値に更新される場合もあります。

注: キー・ジェネレーターを使用するそれぞれのオブジェクトストアは、独立したジェネレーターを持ちます。他のオブジェクトストアとやり取りしても、そのオブジェクトストアのキー・ジェネレーターには影響しません。

キー・ジェネレーターの現在の数値を変更することは、データベース操作の一部とみなされます。 つまり、操作が失敗して元に戻された場合、現在の数値も操作開始前の値に戻されます。 これは、キー・ジェネレーターの利用によって現在の数値が1だけ増加する場合や、 レコードが格納される際に指定されたキー値による変更にも適用されます。

同様に、トランザクションが中断された場合、トランザクションのスコープ内の各オブジェクトストアの キー・ジェネレーターの現在の数値もトランザクション開始前の値に戻されます。

キー・ジェネレーターの現在の数値は、データベース操作が元に戻された場合以外は減少しません。 レコードオブジェクトストアから削除しても、 そのオブジェクトストアのキー・ジェネレーターには影響しません。 たとえばclear() メソッドで全レコードをクリアしても、オブジェクトストアのキー・ジェネレーターの現在の数値は変わりません。

レコードを格納する際、 格納呼び出しでキーが指定されていなければ、キーが生成されます。

オブジェクトストア storeのためにキーを生成するには、以下の手順を実行します:

  1. generatorstoreキー・ジェネレーターとする。

  2. keygenerator現在の数値とする。

  3. もしkeyが253(9007199254740992)より大きければ、失敗を返す。

  4. generator現在の数値を1増やす。

  5. keyを返す。

レコードを格納する際、 格納呼び出しでキーが指定されている場合、関連するキー・ジェネレーターが更新されることがあります。

オブジェクトストア storekeyキー・ジェネレーターを更新する可能性があるには、次の手順を実行します:

  1. keynumberでなければ、これらの手順を中止する。

  2. valuekeyとする。

  3. valuevalueと253(9007199254740992)の最小値にする。

  4. valuevalue以下の最大の整数値にする。

  5. generatorstoreキー・ジェネレーターとする。

  6. もしvaluegenerator現在の数値以上なら、 generator現在の数値value + 1に設定する。

注: キーは、インラインキーを使うオブジェクトストアの場合は、 オブジェクトストアのキー・パスが指すプロパティを格納値に設定することで指定できます。 アウトオブラインキーを使う場合は、格納呼び出し時にキー引数を渡してレコードを保存できます。

指定されたキーのうちnumberのものだけが、 キー・ジェネレーターの現在の数値に影響します。 datearray (含まれる他のキーに関係なく)、binarystring(数値解釈できても)が指定されても、 キー・ジェネレーターの現在の数値には影響しません。 numberで、 が1未満のものは、 常に現在の数値より低いため、影響しません。

キー・ジェネレーターの現在の数値が253(9007199254740992)を超えた場合、 それ以降キー・ジェネレーターで新しいキーを生成しようとすると "ConstraintError" DOMException となります。 ただし、明示的にキーを指定してレコードを挿入することは可能です。 その場合、キー・ジェネレーターを再び使うには、オブジェクトストアを削除して新しく作成し直すしかありません。

注: この制限は、9007199254740992を超える整数がECMAScriptのNumberとして一意に表現できないためです。 例えば、ECMAScriptでは 9007199254740992 + 1 === 9007199254740992 となります。

通常通りキー・ジェネレーターを使う限り、この制限が問題になることはありません。 仮に1秒間に1000回キー生成をし続けても、28万5千年以上この上限には達しません。

この結果、オブジェクトストアで最初に生成されるキーは常に1(より大きい数値キーが先に挿入された場合を除く)であり、 その後生成されるキーは常にストア内で最も大きい数値キーより大きい正の整数となります。 同じオブジェクトストアで同じキーが二度生成されることは、トランザクションがロールバックされない限りありません。

各オブジェクトストアはそれぞれ独自のキー・ジェネレーターを持ちます:

store1 = db.createObjectStore("store1", { autoIncrement: true });
store1.put("a"); // キー1が割り当てられる
store2 = db.createObjectStore("store2", { autoIncrement: true });
store2.put("a"); // キー1が割り当てられる
store1.put("b"); // キー2が割り当てられる
store2.put("b"); // キー2が割り当てられる

挿入が制約違反やIOエラー等で失敗した場合、キー・ジェネレーターは更新されません。

transaction.onerror = function(e) { e.preventDefault() };
store = db.createObjectStore("store1", { autoIncrement: true });
index = store.createIndex("index1", "ix", { unique: true });
store.put({ ix: "a"}); // キー1が割り当てられる
store.put({ ix: "a"}); // 失敗する
store.put({ ix: "b"}); // キー2が割り当てられる

オブジェクトストアからアイテムを削除してもキー・ジェネレーターには影響しません。 clear() を呼び出しても同様です。

store = db.createObjectStore("store1", { autoIncrement: true });
store.put("a"); // キー1
store.delete(1);
store.put("b"); // キー2
store.clear();
store.put("c"); // キー3
store.delete(IDBKeyRange.lowerBound(0));
store.put("d"); // キー4

明示的なキーでアイテムを挿入した場合、キーが数値型かつ最後に生成されたキーより高い場合のみ、キー・ジェネレーターに影響します。

store = db.createObjectStore("store1", { autoIncrement: true });
store.put("a"); // キー1
store.put("b", 3); // キー3(明示的指定)
store.put("c"); // キー4
store.put("d", -10); // キー-10
store.put("e"); // キー5
store.put("f", 6.00001); // キー6.0001(明示的指定)
store.put("g"); // キー7
store.put("f", 8.9999); // キー8.9999(明示的指定)
store.put("g"); // キー9
store.put("h", "foo"); // キー"foo"(明示的指定)
store.put("i"); // キー10
store.put("j", [1000]); // キー[1000](明示的指定)
store.put("k"); // キー11
// これらは、オブジェクトストアがkeyPathを使用し、明示的なキーがオブジェクト内でインライン指定された場合も同様に動作します

トランザクションを中断すると、そのトランザクション内でキー・ジェネレーターが増加した分もロールバックされます。 これは、クラッシュによるロールバックが増加値をコミットできないため、一貫性を保つためです。

db.createObjectStore("store", { autoIncrement: true });
trans1 = db.transaction(["store"], "readwrite");
store_t1 = trans1.objectStore("store");
store_t1.put("a"); // キー1
store_t1.put("b"); // キー2
trans1.abort();
trans2 = db.transaction(["store"], "readwrite");
store_t2 = trans2.objectStore("store");
store_t2.put("c"); // キー1
store_t2.put("d"); // キー2

以下の例は、インラインキーキー・ジェネレーターを使って オブジェクトをオブジェクトストアに保存しようとしたときの異なる挙動を示します。

次の条件がすべて満たされる場合:

この場合、キー・ジェネレーターが生成する値がキー値に使われます。 下記例ではオブジェクトストアのキー・パスは"foo.bar"です。 実際のオブジェクトにはbarプロパティがなく、{ foo: {} }です。 このオブジェクトがオブジェクトストアに保存されると、barプロパティには次のキーである1が割り当てられます。

const store = db.createObjectStore("store", { keyPath: "foo.bar",
                                              autoIncrement: true });
store.put({ foo: {} }).onsuccess = function(e) {
  const key = e.target.result;
  console.assert(key === 1);
};

次の条件がすべて満たされる場合:

この場合、キー・パスプロパティに関連付けられた値が使用されます。 自動生成されたキーは使われません。 下記例ではキー・パスは"foo.bar"で、オブジェクトは{ foo: { bar: 10} }です。 保存時、barプロパティは10のままです。

const store = db.createObjectStore("store", { keyPath: "foo.bar",
                                              autoIncrement: true });
store.put({ foo: { bar: 10 } }).onsuccess = function(e) {
  const key = e.target.result;
  console.assert(key === 10);
};

次の例は、指定されたインラインキーキー・パスで定義されているが、 それに対応するプロパティがない場合の挙動を示します。 この場合、キー・ジェネレーターが生成する値がキー値となり、 必要なプロパティ階層が自動的に作成されます。 下記例ではキー・パスは"foo.bar.baz"で、 オブジェクトは{ zip: {} }です。保存時、foobarbazの各プロパティが 階層的に作成され、次のキーである1がfoo.bar.bazに割り当てられます。

const store = db.createObjectStore("store", { keyPath: "foo.bar.baz",
                                              autoIncrement: true });
store.put({ zip: {} }).onsuccess = function(e) {
  const key = e.target.result;
  console.assert(key === 1);
  store.get(key).onsuccess = function(e) {
    const value = e.target.result;
    // valueは: { zip: {}, foo: { bar: { baz: 1 } } } となる
    console.assert(value.foo.bar.baz === 1);
  };
};

プリミティブ値にプロパティを保存しようとすると失敗し、エラーが投げられます。 最初の例では、オブジェクトストアのキー・パスは"foo"です。 実際のオブジェクトはプリミティブ値4です。 このプリミティブ値にプロパティを定義しようとするため失敗します。

const store = db.createObjectStore("store", { keyPath: "foo", autoIncrement: true });

// キー生成はこのプリミティブ値にkeyPathプロパティを作成しようとする
store.put(4); // DataErrorが投げられる

2.12. レコードスナップショット

レコードスナップショットは、オブジェクトストアレコードまたはインデックスレコードからコピーされたキーおよび値を含みます。

レコードスナップショットは、キーを持ち、それはキーです。

レコードスナップショットは、を持ち、それはです。

注: インデックスレコードの場合、スナップショットのはレコードの参照値のコピーです。 オブジェクトストアレコードの場合、スナップショットのは、レコードの値です。

レコードスナップショットは、さらに主キーを持ち、それはキーです。

注: インデックスレコードの場合、スナップショットの主キーはレコードのであり、それはインデックスの参照先オブジェクトストア内のレコードのキーです。 オブジェクトストアレコードの場合、スナップショットの主キーキーは同じキーであり、それはレコードのキーです。

3. 例外

本書で使用される各例外は、DOMException または DOMExceptionを継承したインターフェースであり、[WEBIDL]で定義されています。

下の表は、本書で使用されているDOMException 名と、その例外の用途説明を示します。

説明
AbortError リクエストが中断されました。
ConstraintError トランザクション内の変更操作が、制約を満たさなかったため失敗しました。
DataCloneError 格納しようとしたデータが、内部の構造化複製アルゴリズムで複製できませんでした。
DataError 操作に渡されたデータが要件を満たしていません。
InvalidAccessError 不正な操作がオブジェクトに対して行われました。
InvalidStateError オブジェクトが許可されていないタイミングや状態で操作が呼び出された場合、または削除・除去されたソースオブジェクトに対してリクエストが行われた場合。
NotFoundError 操作が失敗したのは、要求されたデータベースオブジェクトが見つからなかったためです。
NotReadableError 要求されたデータを含む基盤ストレージが読み取れなかったため、操作が失敗しました。
SyntaxError keyPath引数が不正なキー・パスを含んでいます。
ReadOnlyError 変更操作が読み取り専用トランザクションで試行されました。
TransactionInactiveError 現在アクティブでない、または終了したトランザクションに対してリクエストが行われました。
UnknownError データベース自体とは無関係、または他のエラーでカバーされない一時的な理由で操作が失敗しました。
VersionError 既存より低いバージョンでデータベースを開こうとしました。

上記のDOMException 以外にも、QuotaExceededError 例外型は、残りのストレージ容量が足りない場合や、ストレージの上限に達し、ユーザーがデータベースへの追加容量付与を拒否した場合に使用されます。

注: 複数のIndexed DB操作が同じ型のエラーをスローする可能性があり、1つの操作でも複数の理由で同じ型のエラーとなる場合があるため、 実装では、開発者がエラー原因を特定できるよう、より具体的なメッセージを提供することが推奨されます。

4. API

APIメソッドは、呼び出し元のスレッドをブロックせずに返ります。すべての非同期操作は、直ちにIDBRequest インスタンスを返します。このオブジェクトは、操作の結果に関する情報を最初は持っていません。情報が利用可能になると、リクエスト上でイベントが発火し、その情報がIDBRequest インスタンスのプロパティから取得できるようになります。

これらのタスクのタスクソースは、データベースアクセス・タスクソースです。

データベースタスクをキューするには、タスクをキューするデータベースアクセス・タスクソース上で実行します。

4.1. IDBRequest インターフェース

IDBRequest インターフェースは、データベースデータベースオブジェクトに対する 非同期リクエストの結果にアクセスする手段を、イベントハンドラーIDL属性 [HTML]を使って提供します。

非同期リクエストを行うすべてのメソッドは、 イベントを通じてリクエスト元のアプリケーションと通信する IDBRequest オブジェクトを返します。この設計により、どのデータベースでも 任意の数のリクエストを同時にアクティブにできます。

次の例では、データベースを非同期でオープンしています。 さまざまな状況に応じてイベントハンドラーが登録されています。

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

リクエスト完了時、結果を返します。 リクエストが失敗した場合はundefinedを返します。リクエストがまだ保留中の場合は、 "InvalidStateError" DOMException を投げます。

request . error

リクエスト完了時、エラーDOMException)を返します。 リクエストが成功した場合はnullを返します。リクエストがまだ保留中の場合は "InvalidStateError" DOMException を投げます。

request . source

リクエストが行われたIDBObjectStoreIDBIndex、 またはIDBCursorを返します。 オープンリクエストの場合はnullを返します。

request . transaction

リクエストが行われたIDBTransactionを返します。 オープンリクエストの場合は、アップグレード・トランザクションliveな間はそれを返し、それ以外はnullを返します。

request . readyState

リクエストが完了するまで"pending"を返し、 完了すると"done"を返します。

resultゲッターの手順は以下の通りです:
  1. thisdoneフラグがfalseなら、throw "InvalidStateError" DOMException

  2. thisresultを返す。リクエストがエラーの場合はundefined。

errorゲッターの手順は以下の通りです:
  1. thisdoneフラグがfalseなら、throw "InvalidStateError" DOMException

  2. thiserrorを返す。エラーがない場合はnull。

sourceゲッターの手順は、 thissourceを返す。sourceが設定されていない場合はnull。

transactionゲッターの手順は、 thistransactionを返す。

注記: transaction ゲッターは、open()から返される リクエストなど、特定のリクエストの場合に null を返すことがあります。

readyStateゲッターの手順は、 thisdoneフラグがfalseなら "pending"を返し、 それ以外の場合は "done"を返します。

onsuccess属性は、イベントハンドラーIDL属性であり、 イベントハンドラーイベントタイプsuccessです。

onerror属性は、イベントハンドラーIDL属性であり、 イベントハンドラーイベントタイプerror イベントです。

IDBDatabase のメソッドで オープンリクエストを返すものは、 blocked およびupgradeneeded イベントをリッスンできる拡張インターフェースを使用します。

[Exposed=(Window,Worker)]
interface IDBOpenDBRequest : IDBRequest {
  // Event handlers:
  attribute EventHandler onblocked;
  attribute EventHandler onupgradeneeded;
};

onblocked属性は、イベントハンドラーIDL属性であり、 イベントハンドラーイベントタイプblockedです。

onupgradeneeded属性は、イベントハンドラーIDL属性であり、 イベントハンドラーイベントタイプupgradeneededです。

4.2. イベントインターフェース

この現行標準は、以下のカスタムインターフェースを用いてイベントを発火します:

[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;
};

oldVersionゲッターの手順は、初期化された値を返します。これはデータベースの以前のバージョンを表します。

newVersionゲッターの手順は、初期化された値を返します。これはデータベースの新しいバージョンを表しますが、データベースが削除される場合はnullとなります。データベースをアップグレードする手順も参照してください。

イベントは DOM § 2.5 イベントの構築 に従って構築されます。

バージョン変更イベントを発火するには、名前etargetoldVersionnewVersionを指定して以下の手順を実行します:

  1. eventを、イベントの生成の結果として IDBVersionChangeEventを使って作成する。

  2. eventtype 属性をeに設定する。

  3. eventbubbles およびcancelable 属性をfalseに設定する。

  4. eventoldVersion 属性をoldVersionに設定する。

  5. eventnewVersion 属性をnewVersionに設定する。

  6. legacyOutputDidListenersThrowFlagをfalseにする。

  7. eventをdispatchする。対象はtarget、フラグはlegacyOutputDidListenersThrowFlag

  8. legacyOutputDidListenersThrowFlagを返す。

    注: このアルゴリズムの戻り値は常に使われるとは限りません。

4.3. IDBFactory インターフェース

データベースオブジェクトは、 IDBFactory インターフェースのメソッドを通じてアクセスされます。このインターフェースを実装するオブジェクトは、 Indexed DB操作をサポートする環境のグローバルスコープに1つ存在します。

partial interface mixin WindowOrWorkerGlobalScope {
  [SameObject] readonly attribute IDBFactory indexedDB;
};

indexedDB 属性は、アプリケーションがインデックス付きデータベースの機能にアクセスする仕組みを提供します。

[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)

指定したname接続を現行バージョンで開こうとします。存在しない場合はバージョン1で作成されます。 リクエストが成功すると、requestresult接続となります。

request = indexedDB . open(name, version)

指定したversionname接続を開こうとします。既存データベースのバージョンが低く、開かれた接続versionchange イベントに応じて閉じない場合、すべて閉じるまでリクエストはブロックされ、その後アップグレードが行われます。バージョンが高い場合はリクエストが失敗します。 リクエストが成功すると、requestresult接続になります。

request = indexedDB . deleteDatabase(name)

指定したnameデータベースを削除しようとします。 既存データベースで開かれている 接続versionchange イベントに応じて閉じない場合、すべて閉じるまでリクエストはブロックされます。成功した場合、requestresult はnullになります。

result = await indexedDB . databases()

このプロミスは、ストレージキー内の データベース名とバージョンのスナップショット一覧を返します。

このAPIは、たとえばサイトの以前のバージョンのデータベースをクリーンアップするなど、Webアプリケーションがデータベース利用状況を調べるために設計されています。 結果はスナップショットであり、データ収集やレスポンス配信の順序が、このコンテキストまたは他のコンテキストのデータベース作成・アップグレード・削除リクエストとどのように関連するかについて保証はありません。

open(name, version)メソッドの手順は以下の通りです:

  1. versionが0の場合、throw TypeError

  2. environmentthis関連設定オブジェクトとする。

  3. storageKeyストレージキーの取得environmentを渡して得る。 失敗した場合は、throw "SecurityError" DOMExceptionし、処理を中止する。

  4. requestを新しいオープンリクエストとする。

  5. 以下の手順を並列で実行:

    1. resultデータベース接続を開くの結果とする。引数はstorageKeynameversion(省略時はundefined)、request

      versionが省略された場合は? versionが省略され、指定名のデータベースが既に存在する場合は、バージョン変更なしで接続が開かれます。指定名のデータベースが存在しない場合は、新規にデータベースが作成され、バージョンは1になります。
    2. requestprocessed flagをtrueにする。

    3. データベースタスクをキューして以下を実行:

      1. resultがエラーなら:

        1. requestresultをundefinedに設定。

        2. requesterrorresultに設定。

        3. requestdone flagをtrueに。

        4. errorイベントを発火する。requestが対象。bubblescancelable属性はtrueで初期化。

      2. それ以外の場合:

        1. requestresultresultに設定。

        2. requestdone flagをtrueに。

        3. successイベントを発火する。対象はrequest

        注: 上記の手順でアップグレードトランザクションが実行された場合、これらの手順はそのトランザクション終了後に実行されます。別バージョンアップグレードが直後に発生する場合でも、successイベントは先に接続で発火されるため、スクリプトがversionchangeイベントのリスナーを登録する機会が得られます。

        なぜsuccessイベントの発火errorイベントの発火手順を使わないのか? この時点でリクエストに関連するトランザクションは存在しないため、それらの手順(dispatch前後でトランザクションをactivate/deactivateする)は適用されません。
  6. requestに対して新しいIDBOpenDBRequestオブジェクトを返す。

deleteDatabase(name)メソッドの手順は以下の通り:

  1. environmentthis関連設定オブジェクトとする。

  2. storageKeyストレージキーの取得environmentを渡して得る。 失敗した場合は、throw "SecurityError" DOMExceptionし、処理を中止する。

  3. requestを新しいオープンリクエストとする。

  4. 以下の手順を並列で実行:

    1. resultデータベース削除の結果とする。引数はstorageKeynamerequest

    2. requestprocessed flagをtrueに。

    3. データベースタスクをキューして以下を実行:

      1. resultがエラーなら、 requesterrorresultに設定、 requestdone flagをtrueに、 errorイベント発火(名前はerror、対象はrequest)、 bubblescancelable属性はtrueで初期化。

      2. それ以外の場合、 requestresultをundefinedに、 requestdone flagをtrueに、 バージョン変更イベント発火(名前はsuccess、対象はrequest、引数はresultとnull)。

        なぜsuccessイベントの発火errorイベントの発火手順を使わないのか? このリクエストに関連するトランザクションは存在しないため、それらの手順(dispatch前後でトランザクションをactivate/deactivateする)は適用されません。

        また、このsuccessイベントは IDBVersionChangeEventであり、 oldVersionnewVersionの詳細が含まれます。

  5. requestに対して新しいIDBOpenDBRequestオブジェクトを返す。

databases()メソッドの手順は以下の通り:

  1. environmentthis関連設定オブジェクトとする。

  2. storageKeyストレージキーの取得environmentを渡して得る。 失敗した場合はSecurityError DOMExceptionrejectされたプロミスを返す。

  3. p新しいプロミスとする。

  4. 以下の手順を並列で実行:

    1. databasesstorageKey内の集合からデータベースとして取得する。 何らかの理由で取得できない場合、データベースタスクをキューして、適切なエラー(例:"UnknownError" DOMException)でprejectし、処理終了。

    2. resultを新しいリストとする。

    3. dbについてdatabasesを繰り返す:

      1. dbversionが0なら、continue

      2. infoを新しいIDBDatabaseInfo辞書とする。

      3. infoname辞書メンバーをdbnameに設定。

      4. infoversion辞書メンバーをdbversionに設定。

      5. appendinforesultに追加。

    4. データベースタスクをキューして、resolvepresultを返す。

  5. pを返す。

🚧 databases() メソッドはこの版で新規追加です。 Chrome 71、Edge 79、Firefox 126、Safari 14でサポートされています。 🚧
result = indexedDB . cmp(key1, key2)

2つの値をキーとして比較します。key1key2より前なら-1、key2key1より前なら1、キーが等しければ0を返します。

どちらかの入力が有効なキーでない場合は、"DataError" DOMExceptionをthrowします。

cmp(first, second)メソッドの手順:

  1. a値からキーへの変換firstを渡して得る。例外は再throw。

  2. aが「invalid value」または「invalid type」なら、throw "DataError" DOMException

  3. b値からキーへの変換secondを渡して得る。例外は再throw。

  4. bが「invalid value」または「invalid type」なら、throw "DataError" DOMException

  5. 2つのキーの比較の結果をabで返す。

4.4. IDBDatabase インターフェース

IDBDatabase インターフェースは接続データベースに表現します。

IDBDatabase オブジェクトは、関連する接続close pending flagがfalseで、イベントリスナーが1つ以上登録されていてそのタイプが aborterrorversionchange のいずれかの場合はガベージコレクトされてはなりません。IDBDatabaseオブジェクトがガベージコレクトされた場合、関連する接続閉じる必要があります。

[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;
};
connection . name

データベースのnameを返します。

connection . version

データベースのversionを返します。

nameゲッターの手順は、 thisの関連データベースnameを返すことです。

注: name 属性は、 thisclose pending flagがtrueであってもこの名前を返します。つまり、この属性の値はIDBDatabase インスタンスのライフタイム中は一定です。

versionゲッターの手順は、 thisversionを返すことです。

これはデータベースversionと同じですか? 接続が開いている限り、これは接続されたデータベースversionと同じです。しかし接続閉じると、この属性は後のアップグレードトランザクションによる変更を反映しません。
connection . objectStoreNames

データベース内のオブジェクトストアの名前一覧を返します。

store = connection . createObjectStore(name [, options])

指定したnameoptionsで新しいオブジェクトストアを作成し、新しいIDBObjectStoreを返します。

アップグレードトランザクション外で呼び出すと"InvalidStateError" DOMExceptionをthrowします。

connection . deleteObjectStore(name)

指定したnameオブジェクトストアを削除します。

アップグレードトランザクション外で呼び出すと"InvalidStateError" DOMExceptionをthrowします。

objectStoreNamesゲッターの手順:
  1. namesリストとして、名前オブジェクトストアごとにthisobject store setから取得する。

  2. namesを使い、ソート済み名前リストの作成の結果(DOMStringList)を返す。

これはデータベースオブジェクトストア名前と同じですか? 接続が開いている限り、これは接続されたデータベースオブジェクトストア名前に一致します。ただし、接続閉じると、この属性は後のアップグレードトランザクションの変更を反映しません。

createObjectStore(name, options) メソッドの手順:

  1. databasethisの関連データベースとする。

  2. transactiondatabaseアップグレードトランザクション(nullでなければ)とし、nullの場合はthrow "InvalidStateError" DOMException

  3. transactionstateactiveでなければ、 throw "TransactionInactiveError" DOMException

  4. keyPathoptionskeyPathメンバー(undefinedまたはnullでなければ)とし、それ以外はnull。

  5. keyPathがnullでなく、有効なkey pathでなければ、throw "SyntaxError" DOMException

  6. databasenameオブジェクトストアが既に存在する場合、throw "ConstraintError" DOMException

  7. autoIncrementoptionsautoIncrement メンバーとする。

  8. autoIncrementがtrueで、keyPathが空文字列または任意のシーケンス(空でも可)の場合、throw "InvalidAccessError" DOMException

  9. storedatabase内の新しいオブジェクトストアとし、作成したオブジェクトストアnamenameに設定。autoIncrementがtrueなら、作成したオブジェクトストアキー・ジェネレーターを使用する。keyPathがnullでなければ、作成したオブジェクトストアkey pathkeyPathに設定。

  10. storeおよびtransactionに関連付けられた新しいオブジェクトストアハンドルを返す。

このメソッドは、指定した名前で接続されたデータベースに新しいオブジェクトストアを作成して返します。このメソッドはアップグレードトランザクション内のみで呼び出す必要があります。

このメソッドは、呼び出したobjectStoreNames プロパティを同期的に変更します。

一部の実装では、createObjectStore() メソッドが返った後、オブジェクトストア作成タスクをキューした後に問題が発生する場合があります。例えば、新しく作成されたオブジェクトストアのメタデータをデータベースに非同期で挿入する実装や、クォータの理由でユーザーの許可を求める必要がある場合です。 そのような実装でもIDBObjectStoreオブジェクトを作成して返し、作成が失敗した場合は適切なエラー(例えばクォータ理由の場合はQuotaExceededError)を使ってトランザクションを中止する必要があります。

deleteObjectStore(name)メソッドの手順:

  1. databasethisの関連データベースとする。

  2. transactiondatabaseアップグレードトランザクション(nullでなければ)とし、nullの場合はthrow "InvalidStateError" DOMException

  3. transactionstateactiveでなければ、 throw "TransactionInactiveError" DOMException

  4. databasenameオブジェクトストアがなければ、throw "NotFoundError" DOMException

  5. storethisobject store setから削除。

  6. storetransactionに関連するオブジェクトストアハンドルがあれば、そのindex setのエントリをすべて削除。

  7. storeを破棄。

このメソッドは、指定した名前の接続されたデータベース内のオブジェクトストアを破棄します。このメソッドはアップグレードトランザクション内のみで呼び出す必要があります。

このメソッドは、呼び出したobjectStoreNames プロパティを同期的に変更します。

transaction = connection . transaction(scope [, mode [, options ] ])

指定したscope(単一のオブジェクトストアまたは複数名の配列)、mode("readonly"または"readwrite")、および追加optionsdurability:"default"、"strict"、"relaxed")で新しいトランザクションを返します。

modeのデフォルトは"readonly"、durabilityのデフォルトは"default"です。

connection . close()

すべての実行中のトランザクションが完了した後に接続を閉じます。

transaction(storeNames, mode, options) メソッドの手順:

  1. この接続に関連付けられたアップグレードトランザクションがライブなら、throw "InvalidStateError" DOMException

  2. thisclose pending flagがtrueなら、throw "InvalidStateError" DOMException

  3. scopeを、storeNamesがシーケンスなら一意な文字列の集合、そうでなければstoreNamesのみを含む集合とする。

  4. scope内のいずれかの文字列が、接続されたデータベースオブジェクトストア名でなければ、throw "NotFoundError" DOMException

  5. scopeが空なら、throw "InvalidAccessError" DOMException

  6. modeが"readonly"または"readwrite"でなければ、 throw TypeError

  7. transactionを新しく作成したトランザクション(接続、modeoptionsdurabilityメンバー、scope内のオブジェクトストアセット)とする。

  8. transactioncleanup event loopを現在のevent loopに設定。

  9. transactionを表すIDBTransactionオブジェクトを返す。

🚧 durability オプションはこの版で新規追加です。 Chrome 82、Edge 82、Firefox 126、Safari 15でサポートされています。 🚧

注: 作成されたtransactionライフタイムのルールに従います。

close()メソッドの手順:

  1. この接続データベース接続を閉じるを実行する。

注: 接続は、すべての未完了トランザクションが完了するまで実際には閉じませんclose()を複数回呼んでも効果はありません。

onabort属性は、イベントハンドラーIDL属性であり、 イベントハンドラーイベントタイプabortです。

onclose属性は、イベントハンドラーIDL属性であり、 イベントハンドラーイベントタイプcloseです。

onerror属性は、イベントハンドラーIDL属性であり、 イベントハンドラーイベントタイプerrorです。

onversionchange属性は、イベントハンドラーIDL属性であり、 イベントハンドラーイベントタイプversionchangeです。

4.5. IDBObjectStore インターフェイス

IDBObjectStore インターフェイスは、オブジェクトストアハンドルを表します。

[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";
};
store . name

ストアの名前を返します。

store . name = newName

ストアの名前newNameに更新します。

アップグレードトランザクション内で呼び出されない場合は、"InvalidStateError" DOMException がスローされます。

store . keyPath

ストアのキー・パスを返します。存在しない場合はnullです。

store . indexNames

ストア内のインデックス名のリストを返します。

store . transaction

関連するトランザクションを返します。

store . autoIncrement

ストアがキー生成器を持つ場合はtrue、そうでない場合はfalseを返します。

nameのgetter手順は、this名前を返します。

これはオブジェクトストア名前と同じですか? トランザクション終了していない限り、 これは関連するオブジェクトストア名前と同じです。しかしトランザクション終了した後は、 この属性は後のアップグレードトランザクションによる変更を反映しません。

nameのsetter手順:

  1. name与えられた値とする。

  2. transactionthisトランザクションとする。

  3. storethisオブジェクトストアとする。

  4. storeが削除されていた場合、 throw "InvalidStateError" DOMException

  5. transactionアップグレードトランザクションでない場合、 throw "InvalidStateError" DOMException

  6. transaction状態activeでない場合、 throw "TransactionInactiveError" DOMException

  7. store名前nameと等しい場合、これらの手順を終了する。

  8. storeデータベース内にnameというオブジェクトストア がすでに存在する場合、throw "ConstraintError" DOMException

  9. store名前nameに設定する。

  10. this名前nameに設定する。

keyPathのgetter手順は、 thisオブジェクトストアキー・パスを返し、存在しない場合はnullを返します。キー・パスDOMString (文字列の場合)または sequence<DOMString> (文字列リストの場合)として変換されます。[WEBIDL]参照。

NOTE: 返される値は、オブジェクトストア作成時に使用されたインスタンスと同じではありません。 しかし、この属性がオブジェクト(特にArray)を返す場合、 参照するたびに同じオブジェクトインスタンスが返されます。オブジェクトのプロパティを変更しても オブジェクトストアには影響しません。

indexNamesのgetter手順:
  1. namesリストとして、名前の一覧とし、インデックスの集合をthisインデックス集合から取得する。

  2. 結果(DOMStringList)として ソート済みの名前リストを作成し、namesで返す。

これはオブジェクトストアインデックス名前リストと同じですか? トランザクション終了していない限り、 これは関連するオブジェクトストアインデックス名前リストと同じです。しかし トランザクション終了した後は、 この属性は後のアップグレードトランザクションによる変更を反映しません。

transactionのgetter手順は、 thisトランザクションを返します。

autoIncrementのgetter手順は、 thisオブジェクトストアキー生成器を持つ場合はtrue、そうでない場合はfalseを返します。

以下のメソッドは、読み取り専用トランザクション内で呼び出される場合 "ReadOnlyError" DOMException がスローされ、 トランザクションactiveでない場合は "TransactionInactiveError" DOMException がスローされます。
request = store . put(value [, key])
request = store . add(value [, key])

valuekeyでストア内にレコードを追加または更新します。

ストアがインラインキーを使用していてkeyが指定された場合、 "DataError" DOMException がスローされます。

put() を使用した場合、同じキーを持つ既存のレコードは置き換えられます。add() を使用した場合、同じキーを持つ レコードが既に存在すると requestは失敗し、requesterror が"ConstraintError" DOMExceptionとなります。

成功した場合、requestresultレコードキーとなります。

request = store . delete(query)

queryで指定したキーまたはキー範囲に該当する レコードをストアから削除します。

成功した場合、requestresultundefinedです。

request = store . clear()

ストア内のすべてのレコードを削除します。

成功した場合、requestresultundefinedです。

put(value, key) メソッドの手順は、 追加または更新thisvaluekey、および no-overwrite flag を false で実行した結果を返します。

add(value, key) メソッドの手順は、 追加または更新thisvaluekey、および no-overwrite flag を true で実行した結果を返します。

追加または更新handlevaluekeyno-overwrite flag で実行するには、次の手順を行います:

  1. transactionhandleトランザクション とする。

  2. storehandleオブジェクトストア とする。

  3. store が削除されている場合、 throw "InvalidStateError" DOMException を投げる。

  4. transaction状態active でない場合、 throw "TransactionInactiveError" DOMException を投げる。

  5. transaction読み取り専用トランザクション の場合、 throw "ReadOnlyError" DOMException を投げる。

  6. storeインラインキー を使用していて key が指定された場合、 throw "DataError" DOMException を投げる。

  7. storeアウトオブラインキー を使用していて キー生成器 を持たず key が指定されていない場合、throw "DataError" DOMException を投げる。

  8. key が指定された場合、次を行う:

    1. r値からキーへの変換key で実行した結果とする。例外は再スローする。

    2. r が "invalid value" または "invalid type" の場合、 throw "DataError" DOMException を投げる。

    3. keyr とする。

  9. targetRealm をユーザーエージェント定義の Realm とする。

  10. clonetransaction の間に targetRealm 内で valueクローンとする。例外は再スローする。

    なぜ値のコピーを作成するのか? 値は保存時にシリアライズされます。ここでコピーとして扱うことで、 この仕様の他のアルゴリズムが ECMAScript の値として扱えますが、 実装は挙動の違いが観測できない場合は最適化してよいです。
  11. storeインラインキー を使用している場合、次を行う:

    1. kpkキー・パスで値からキーを抽出clonestoreキー・パス で実行した結果とする。例外は再スローする。

    2. kpk が無効なら、throw "DataError" DOMException を投げる。

    3. kpk が失敗でなければ、keykpk とする。

    4. それ以外の場合(kpk が失敗):

      1. storeキー生成器を持たない場合、 throw "DataError" DOMException を投げる。

      2. 値へキーを注入できるか確認clonestoreキー・パス で実行し false を返した場合、throw "DataError" DOMException を投げる。

  12. operationレコードをオブジェクトストアに保存storeclonekeyno-overwrite flag で実行するアルゴリズムとする。

  13. 結果(IDBRequest)として、 非同期でリクエストを実行handleoperation で実行した結果を返す。

delete(query) メソッドの手順:

  1. transactionthisトランザクションとする。

  2. storethisオブジェクトストアとする。

  3. store が削除されている場合、throw "InvalidStateError" DOMException を投げる。

  4. transaction状態active でない場合、 throw "TransactionInactiveError" DOMException を投げる。

  5. transaction読み取り専用トランザクション の場合、 throw "ReadOnlyError" DOMException を投げる。

  6. range値からキー範囲への変換query と true で実行した結果とする。例外は再スローする。

  7. operationオブジェクトストアからレコードを削除storerange で実行するアルゴリズムとする。

  8. 結果(IDBRequest)として、 非同期でリクエストを実行thisoperation で実行した結果を返す。

NOTE: query パラメータは、キー または キー範囲IDBKeyRange) であり、削除対象の レコード を指定します。

注意: 他のキーやキー範囲を受け取るメソッドと異なり、このメソッドでは nullをキーとして渡すことはできません。これは、些細なバグによってオブジェクトストア全体が消去されるリスクを低減するためです。

clear() メソッドの手順:

  1. transactionthisトランザクションとする。

  2. storethisオブジェクトストアとする。

  3. store が削除されている場合、throw "InvalidStateError" DOMException を投げる。

  4. transaction状態active でない場合、 throw "TransactionInactiveError" DOMException を投げる。

  5. transaction読み取り専用トランザクション の場合、 throw "ReadOnlyError" DOMException を投げる。

  6. operationオブジェクトストアを空にするstore で実行するアルゴリズムとする。

  7. 結果(IDBRequest)として、 非同期でリクエストを実行thisoperation で実行した結果を返す。

以下のメソッドは、トランザクションactiveでない場合、 "TransactionInactiveError" DOMException をスローします。
request = store . get(query)

指定されたquery内のキーまたはキー範囲に一致する 最初のレコードを取得します。

成功した場合、requestresultとなります。該当する レコードがなければ undefined となります。

request = store . getKey(query)

指定されたquery内のキーまたはキー範囲に一致する 最初のレコードキーを取得します。

成功した場合、requestresultキーとなります。該当する レコードがなければ undefined となります。

request = store . getAll(query [, count])
request = store . getAll({query, count, direction})

指定されたquery内のキーまたはキー範囲に一致するレコードを取得します(countが指定されていれば、その件数まで)。 directionオプションに"next"を設定すると最初のcount件の値を取得し、 "prev"を設定すると最後のcount件の値を返します。

成功した場合、requestresultArrayとなり、が格納されます。

request = store . getAllKeys(query [, count])
request = store . getAllKeys({query, count, direction})

指定されたquery内のキーまたはキー範囲に一致するレコードキーを取得します(countが指定されていれば、その件数まで)。 directionオプションに"next"を設定すると最初のcount件のキーを取得し、 "prev"を設定すると最後のcount件のキーを返します。

成功した場合、requestresultArrayとなり、キーが格納されます。

request = store . getAllRecords({query, count, direction})

レコードキーを取得します。

queryオプションで一致するキーまたはキー範囲を指定します。 countオプションで一致するレコード数を制限できます。 directionオプションに"next"を設定すると最初のcount件のレコードを取得し、 "prev"を設定すると最後のcount件のレコードを返します。

成功した場合、requestresultArrayとなり、 各メンバーはIDBRecordです。

request = store . count(query)

指定されたquery内のキーまたはキー範囲に一致する レコードの件数を取得します。

成功した場合、requestresult は件数となります。

get(query) メソッドの手順:

  1. transactionthisトランザクションとする。

  2. storethisオブジェクトストアとする。

  3. store が削除されている場合、throw "InvalidStateError" DOMException を投げる。

  4. transaction状態active でない場合、 throw "TransactionInactiveError" DOMException を投げる。

  5. range値からキー範囲への変換query と true で実行した結果とする。例外は再スローする。

  6. operationオブジェクトストアから値を取得現在の Realm レコードstorerange で実行するアルゴリズムとする。

  7. 結果(IDBRequest)として、 非同期でリクエストを実行thisoperation で実行した結果を返す。

注意: query パラメータは、キー または キー範囲IDBKeyRange)であり、 取得対象のレコード値を指定します。範囲を指定した場合は、その範囲で最初に存在する値を取得します。

注意: このメソッドは、指定したキーのレコードが存在しない場合と、値がundefinedである場合の結果が同じです。 両者を区別する必要がある場合は、同じキーでopenCursor() を使用してください。この場合、レコードが存在すれば値がundefinedのカーソルが返され、存在しなければカーソルは返されません。

getKey(query) メソッドの手順:

  1. transactionthisトランザクションとする。

  2. storethisオブジェクトストアとする。

  3. store が削除されている場合、throw "InvalidStateError" DOMException を投げる。

  4. transaction状態active でない場合、 throw "TransactionInactiveError" DOMException を投げる。

  5. range値からキー範囲への変換query と true で実行した結果とする。例外は再スローする。

  6. operationオブジェクトストアからキーを取得storerange で実行するアルゴリズムとする。

  7. 結果(IDBRequest)として、 非同期でリクエストを実行thisoperation で実行した結果を返す。

注意: query パラメータは、キー または キー範囲IDBKeyRange)であり、 取得対象のレコードキーを指定します。範囲を指定した場合は、その範囲で最初に存在するキーを取得します。

getAll(queryOrOptions, count) メソッドの手順:

  1. 複数項目取得リクエストの作成現在の Realm レコードthis、"value"、 queryOrOptions、および指定されていれば count で実行した結果を返す。 例外は再スローする。

getAllKeys(queryOrOptions, count) メソッドの手順:

  1. 複数項目取得リクエストの作成現在の Realm レコードthis、"key"、 queryOrOptions、および指定されていれば count で実行した結果を返す。 例外は再スローする。

getAllRecords(options) メソッドの手順:

  1. 複数項目取得リクエストの作成現在の Realm レコードthis、"record"、 options で実行した結果を返す。 例外は再スローする。

count(query) メソッドの手順:

  1. transactionthisトランザクションとする。

  2. storethisオブジェクトストアとする。

  3. store が削除されている場合、throw "InvalidStateError" DOMException を投げる。

  4. transaction状態active でない場合、 throw "TransactionInactiveError" DOMException を投げる。

  5. range値からキー範囲への変換query で実行した結果とする。 例外は再スローする。

  6. operation範囲内レコード件数取得storerange で実行するアルゴリズムとする。

  7. 結果(IDBRequest)として、 非同期でリクエストを実行thisoperation で実行した結果を返す。

注意: query パラメータは、キー または キー範囲IDBKeyRange)であり、 件数取得対象のレコードを指定します。nullまたは未指定の場合は 制限なしのキー範囲が使用されます。

以下のメソッドは、トランザクションactiveでない場合、 "TransactionInactiveError" DOMException をスローします。
request = store . openCursor([query [, direction = "next"]])

queryに一致するレコードdirectionの順で走査するカーソルを開きます。 queryがnullの場合、store内のすべてのレコードが対象となります。

成功した場合、requestresultIDBCursorWithValue で、最初の一致するレコードを指します。一致するレコードがない場合はnullです。

request = store . openKeyCursor([query [, direction = "next"]])

キーのみフラグを true にした カーソルqueryに一致するレコードdirectionの順で走査します。 queryがnullの場合、store内のすべてのレコードが対象となります。

成功した場合、requestresultIDBCursor で、最初の一致するレコードを指します。一致するレコードがない場合はnullです。

openCursor(query, direction) メソッドの手順:

  1. transactionthisトランザクションとする。

  2. storethisオブジェクトストアとする。

  3. store が削除されている場合、throw "InvalidStateError" DOMException を投げる。

  4. transaction状態active でない場合、 throw "TransactionInactiveError" DOMException を投げる。

  5. range値からキー範囲への変換query で実行した結果とする。 例外は再スローする。

  6. cursor を新しいカーソルとし、 ソースハンドルthisに設定し、 位置は未定義、 方向direction値取得フラグはfalse、 キーは未定義、 範囲rangeキーのみフラグはfalseに設定する。

  7. operationカーソルを反復現在の Realm レコードcursorで実行するアルゴリズムとする。

  8. request非同期でリクエストを実行thisoperation で実行した結果とする。

  9. cursorrequestrequestに設定する。

  10. request を返す。

注意: query パラメータは、キー または キー範囲IDBKeyRange)であり、 カーソルの範囲として使用されます。 nullまたは未指定の場合は制限なしのキー範囲が使用されます。

openKeyCursor(query, direction) メソッドの手順:

  1. transactionthisトランザクションとする。

  2. storethisオブジェクトストアとする。

  3. store が削除されている場合、throw "InvalidStateError" DOMException を投げる。

  4. transaction状態active でない場合、 throw "TransactionInactiveError" DOMException を投げる。

  5. range値からキー範囲への変換query で実行した結果とする。 例外は再スローする。

  6. cursor を新しいカーソルとし、 ソースハンドルthisに設定し、 位置は未定義、 方向direction値取得フラグはfalse、 キーは未定義、 範囲rangeキーのみフラグはtrueに設定する。

  7. operationカーソルを反復現在の Realm レコードcursorで実行するアルゴリズムとする。

  8. request非同期でリクエストを実行thisoperation で実行した結果とする。

  9. cursorrequestrequestに設定する。

  10. request を返す。

注意: query パラメータは、キー または キー範囲IDBKeyRange)であり、 カーソルの範囲として使用されます。nullまたは未指定の場合は 制限なしのキー範囲が使用されます。

index = store . index(name)

store内でnameという名前のインデックスに対応する IDBIndexを返します。

index = store . createIndex(name, keyPath [, options])

store内で指定されたnamekeyPathoptionsで新しいインデックスを作成し、新しいIDBIndexを返します。 もしkeyPathoptionsで定義された制約がstore内の既存データで満たせない場合、アップグレードトランザクション中断され、 "ConstraintError" DOMExceptionがスローされます。

アップグレードトランザクション内で呼び出されない場合は、 "InvalidStateError" DOMExceptionがスローされます。

store . deleteIndex(name)

store内で指定されたnameインデックスを削除します。

アップグレードトランザクション内で呼び出されない場合は、 "InvalidStateError" DOMExceptionがスローされます。

createIndex(name, keyPath, options) メソッドの手順:

  1. transactionthisトランザクションとする。

  2. storethisオブジェクトストアとする。

  3. transactionアップグレードトランザクションでない場合、 throw "InvalidStateError" DOMException を投げる。

  4. store が削除されている場合、throw "InvalidStateError" DOMException を投げる。

  5. transaction状態active でない場合、 throw "TransactionInactiveError" DOMException を投げる。

  6. storenameというインデックスがすでに存在する場合、 throw "ConstraintError" DOMException を投げる。

  7. keyPath有効なキー・パスでない場合、throw "SyntaxError" DOMException を投げる。

  8. uniqueoptionsunique メンバーとする。

  9. multiEntryoptionsmultiEntry メンバーとする。

  10. keyPath がシーケンスでmultiEntryがtrueの場合、 throw "InvalidAccessError" DOMException を投げる。

  11. indexstoreに新しく作成したインデックスとする。 index名前nameキー・パスkeyPath一意フラグuniquemultiEntryフラグmultiEntryを設定する。

  12. indexthisインデックス集合に追加する。

  13. 新しいインデックスハンドルindexおよびthisに関連付けて返す。

このメソッドは、指定された名前でオブジェクトストアに 新しいインデックスを作成して返します。 このメソッドはアップグレードトランザクションからのみ呼び出す必要があります。

作成するインデックスには、インデックスが参照するオブジェクトストアのデータに対する制約(例えばインデックスの キー・パスによる値の一意性)を含めることができます。 既に参照先のオブジェクトストアにその制約に違反するデータがある場合でも、 createIndex() の実装が例外を投げたり動作に影響を与えたりしてはいけません。 必ずIDBIndexオブジェクトを作成して返し、 データベースタスクをキューして createIndex()呼び出しで使用された アップグレードトランザクションを中断します。

このメソッドは、呼び出したIDBObjectStore インスタンスのindexNames プロパティを同期的に変更します。 このメソッドはIDBRequest オブジェクトは返しませんが、インデックスの作成自体は アップグレードトランザクション内で非同期リクエストとして処理されます。

一部の実装では、createIndexメソッドの戻り値返却後にインデックス作成で非同期的に問題が発生する場合があります。 例えば新しく作成したインデックスのメタデータを非同期でデータベースに挿入する場合や、クォータの関係でユーザーの許可が必要な場合などです。 その場合でもIDBIndexオブジェクトは必ず作成・返却され、 作成失敗が判明した際には適切なエラーでトランザクションを中断する手順を実行する必要があります。 例えばインデックス作成がクォータの理由で失敗した場合は QuotaExceededError をエラーとして使用し、一意性制約違反の場合は "ConstraintError" DOMException をエラーとして使用します。

インデックスの非同期作成は以下の例で観察できます:

const request1 = objectStore.put({name: "betty"}, 1);
const request2 = objectStore.put({name: "betty"}, 2);
const index = objectStore.createIndex("by_name", "name", {unique: true});

createIndex() が呼び出された時点では、どちらの リクエストも実行されていません。2つ目のリクエストが実行されると、重複したnameが作成されます。 インデックス作成は非同期リクエストとみなされるため、インデックスの一意性制約 で2つ目の リクエストが失敗することはありません。 代わりに、インデックス作成時に制約が失敗した際にトランザクション中断されます。

index(name) メソッドの手順:

  1. transactionthisトランザクションとする。

  2. storethisオブジェクトストアとする。

  3. store が削除されている場合、throw "InvalidStateError" DOMException を投げる。

  4. transaction状態finishedの場合、 throw "InvalidStateError" DOMException を投げる。

  5. indexインデックス namethisインデックス集合に存在すればそれとし、存在しなければ throw "NotFoundError" DOMException を投げる。

  6. indexおよびthisに関連付けた インデックスハンドルを返す。

注意: 同じIDBObjectStoreインスタンスで 同じnameを指定してこのメソッドを呼び出すと、同じIDBIndexインスタンスが返されます。

注意: 返されるIDBIndexインスタンスは このIDBObjectStoreインスタンス専用です。 別のIDBObjectStoreインスタンスで 同じnameを指定して呼び出した場合は、別のIDBIndexインスタンスが返されます。

deleteIndex(name) メソッドの手順:

  1. transactionthisトランザクションとする。

  2. storethisオブジェクトストアとする。

  3. transactionアップグレードトランザクションでない場合、 throw "InvalidStateError" DOMException を投げる。

  4. store が削除されている場合、throw "InvalidStateError" DOMException を投げる。

  5. transaction状態active でない場合、 throw "TransactionInactiveError" DOMException を投げる。

  6. storenameインデックスが存在すればそれをindexとし、存在しなければ throw "NotFoundError" DOMException を投げる。

  7. indexthisインデックス集合から削除する。

  8. index を破棄する。

このメソッドは、指定された名前のインデックスオブジェクトストアから破棄します。 このメソッドはアップグレードトランザクション内からのみ呼び出す必要があります。

このメソッドは、呼び出したIDBObjectStore インスタンスのindexNames プロパティを同期的に変更します。 このメソッドはIDBRequest オブジェクトは返しませんが、インデックスの破棄自体は アップグレードトランザクション内で非同期リクエストとして処理されます。

4.6. IDBIndex インターフェイス

IDBIndex インターフェイスは、インデックスハンドルを表します。

[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");
};
index . name

インデックスのnameを返します。

index . name = newName

ストアのnamenewNameに更新します。

アップグレードトランザクション内で呼び出されない場合、"InvalidStateError" DOMException がスローされます。

index . objectStore

インデックスが属しているIDBObjectStoreを返します。

index . keyPath

インデックスのkey pathを返します。

index . multiEntry

インデックスのmultiEntry flagがtrueの場合、trueを返します。

index . unique

インデックスのunique flagがtrueの場合、trueを返します。

nameゲッターの手順は、thisnameを返すことです。

これはindexnameと同じですか? トランザクション終了していなければ、 これは関連するindexnameと同じです。ただし、トランザクション終了した後は、 この属性は後のアップグレードトランザクションで行われた変更を反映しません。

name セッターの手順は以下の通りです:

  1. name与えられた値とする。

  2. transactionthistransactionとする。

  3. indexthisindexとする。

  4. もしtransactionアップグレードトランザクションでなければ、 throwし、"InvalidStateError" DOMExceptionとする。

  5. もしtransactionstateactiveでなければ、 throwし、"TransactionInactiveError" DOMExceptionとする。

  6. もしindexまたはindexオブジェクトストアが 削除されていた場合、throwし、"InvalidStateError" DOMExceptionとする。

  7. もしindexnamenameと等しければ、これらの手順を終了する。

  8. もしindexオブジェクトストアnameというindex nameが既に存在する場合、 throwし、"ConstraintError" DOMExceptionとする。

  9. indexnamenameに設定する。

  10. thisnamenameに設定する。

objectStoreゲッターの手順は、thisオブジェクトストアハンドルを返すことです。

keyPathゲッターの手順は、thisindexkey pathを返すことです。 key pathDOMString (文字列の場合)または sequence<DOMString> (文字列リストの場合)として変換されます。[WEBIDL]参照。

NOTE: 返される値は、 index作成時に使用されたインスタンスと同じではありません。ただし、 この属性がオブジェクト(特にArray)を返す場合、 毎回同じオブジェクトインスタンスが返されます。オブジェクトのプロパティを変更しても indexには影響しません。

multiEntryゲッターの手順は、thisindexmultiEntry flagを返すことです。

uniqueゲッターの手順は、thisindexunique flagを返すことです。

次のメソッドは、トランザクションactiveでない場合、 "TransactionInactiveError" DOMException をスローします。
request = index . get(query)

指定したquery内のkeyまたはkey rangeに一致する 最初のレコードを取得します。

成功すると、requestresultとなり、一致する レコードがなければundefinedとなります。

request = index . getKey(query)

queryで指定したキーまたはキー範囲に一致する最初のレコードキーを取得します。

成功すると、requestresultキーとなり、一致するレコードがなければundefinedとなります。

request = index . getAll(query [, count])
request = index . getAll({query, count, direction})

queryで指定したキーまたはキー範囲に一致するレコードを取得します(countが指定されている場合は最大count件)。 directionオプションに"next"を指定すると先頭からcount件の値を取得し、 "prev"を指定すると末尾からcount件の値を取得します。 "nextunique"または"prevunique"を指定すると、重複したインデックスキーのレコードは最初の一致したレコードのみ取得し、それ以降は除外します。

成功すると、requestresultArrayとなります。

request = index . getAllKeys(query [, count])
request = index . getAllKeys({query, count, direction})

queryで指定したキーまたはキー範囲に一致するレコードキーを取得します(countが指定されている場合は最大count件)。 directionオプションに"next"を指定すると先頭からcount件のキーを取得し、 "prev"を指定すると末尾からcount件のキーを取得します。 "nextunique"または"prevunique"を指定すると、重複したインデックスキーのレコードは最初の一致したレコードのみ取得し、それ以降は除外します。

成功すると、requestresultキーArrayとなります。

request = index . getAllRecords({query, count, direction})

レコードキー、およびインデックスキーを取得します。

queryオプションで一致するキーまたはキー範囲を指定します。 countオプションで一致するレコード数の上限を指定できます。 directionオプションに"next"を指定すると先頭からcount件のレコードを取得し、 "prev"を指定すると末尾からcount件のレコードを取得します。 "nextunique"または"prevunique"を指定すると、重複したインデックスキーのレコードは最初の一致したレコードのみ取得し、それ以降は除外します。

成功すると、requestresultArrayとなり、各要素はIDBRecordです。 レコードのインデックスキーIDBRecordのkeyで取得でき、キーIDBRecordのprimaryKeyで取得できます。

指定したquery内のkey またはkey rangeに一致するレコードの数を取得します。

成功すると、requestresult は 件数となります。

get(query) メソッドの手順は以下の通りです:

  1. transactionthistransactionとする。

  2. indexthisindexとする。

  3. もしindexまたはindexオブジェクトストアが削除されていた場合、 throwし、"InvalidStateError" DOMExceptionとする。

  4. もしtransactionstateactiveでなければ、 throwし、"TransactionInactiveError" DOMExceptionとする。

  5. rangequeryとtrueを使って値をキー範囲へ変換するの結果とする。例外があれば再スローする。

  6. operationインデックスから参照値を取得するアルゴリズム(現在のRealmレコード, index, range)で実行するものとする。

  7. 非同期でリクエストを実行するthisoperationで実行した結果(IDBRequest)を返す。

注意: queryパラメータはkeyまたはkey rangeIDBKeyRange)で、 取得したい参照値を特定します。範囲が指定された場合、その範囲内の最初の既存レコードを取得します。

注意: このメソッドは、指定したキーにレコードが存在しない場合も、値がundefinedのレコードが存在する場合も、同じ結果を返します。 両者を区別したい場合は、同じキーでopenCursor() を利用してください。レコードが存在すれば値はundefined、存在しなければカーソル自体が返りません。

getKey(query) メソッドの手順は以下の通りです:

  1. transactionthistransactionとする。

  2. indexthisindexとする。

  3. もしindexまたはindexオブジェクトストアが削除されていた場合、 throwし、"InvalidStateError" DOMExceptionとする。

  4. もしtransactionstateactiveでなければ、 throwし、"TransactionInactiveError" DOMExceptionとする。

  5. rangequeryとtrueを使って値をキー範囲へ変換するの結果とする。例外があれば再スローする。

  6. operationインデックスから値を取得するアルゴリズム(index, range)で実行するものとする。

  7. 非同期でリクエストを実行するthisoperationで実行した結果(IDBRequest)を返す。

注意: queryパラメータはkeyまたはkey rangeIDBKeyRange)で、 取得したいレコードのキーを特定します。範囲が指定された場合、その範囲内の最初の既存キーを取得します。

getAll(queryOrOptions, count) メソッドの手順は以下の通りです:

  1. 複数項目を取得するリクエストを作成する現在のRealmレコード, this, "value", queryOrOptions, count(指定されていれば)で実行した結果を返す。例外は再スローする。

getAllKeys(queryOrOptions, count) メソッドの手順は以下の通りです:

  1. 複数項目を取得するリクエストを作成する現在のRealmレコード, this, "key", queryOrOptions, count(指定されていれば)で実行した結果を返す。例外は再スローする。

getAllRecords(options) メソッドの手順は以下の通りです:

  1. 複数項目を取得するリクエストを作成する現在のRealmレコード, this, "record", optionsで実行した結果を返す。例外は再スローする。

count(query) メソッドの手順は以下の通りです:

  1. transactionthistransactionとする。

  2. indexthisindexとする。

  3. もしindexまたはindexオブジェクトストアが削除されていた場合、 throwし、"InvalidStateError" DOMExceptionとする。

  4. もしtransactionstateactiveでなければ、 throwし、"TransactionInactiveError" DOMExceptionとする。

  5. rangequeryを使って値をキー範囲へ変換するの結果とする。 例外があれば再スローする。

  6. operation範囲内のレコード数を数えるアルゴリズム(index, range)で実行するものとする。

  7. 非同期でリクエストを実行するthisoperationで実行した結果(IDBRequest)を返す。

注意: queryパラメータはkeyまたはkey rangeIDBKeyRange)で、 カウント対象のレコードを特定します。nullまたは未指定の場合、無制限キー範囲が使われます。

次のメソッドは、トランザクションactiveでない場合、 "TransactionInactiveError" DOMException をスローします。
request = index . openCursor([query [, direction = "next"]])

queryに一致するレコードdirectionで並べてカーソルを開きます。 queryがnullの場合、indexのすべてのレコードが対象となります。

成功すると、requestresultIDBCursorWithValue 型、マッチする レコードがなければnullです。

request = index . openKeyCursor([query [, direction = "next"]])

queryに一致するレコードdirectionで並べて key only flagをtrueにして カーソルを開きます。 queryがnullの場合、indexのすべてのレコードが対象となります。

成功すると、requestresultIDBCursor 型、マッチするレコードがなければnullです。

openCursor(query, direction) メソッドの手順は以下の通りです:

  1. transactionthistransactionとする。

  2. indexthisindexとする。

  3. もしindexまたはindexオブジェクトストアが削除されていた場合、 throwし、"InvalidStateError" DOMExceptionとする。

  4. もしtransactionstateactiveでなければ、 throwし、"TransactionInactiveError" DOMExceptionとする。

  5. rangequeryを使って値をキー範囲へ変換するの結果とする。 例外があれば再スローする。

  6. cursorを新しいカーソルとし、 source handlethisに設定し、 positionを未定義にし、 directiondirectionに設定し、 got value flagをfalseにし、 keyvalueを未定義にし、 rangerangeに設定し、 key only flagをfalseに設定する。

  7. operationカーソルを反復処理するアルゴリズム(現在のRealmレコード, cursor)で実行するものとする。

  8. request非同期でリクエストを実行するthisoperationで実行した結果とする。

  9. cursorrequestrequestに設定する。

  10. requestを返す。

注意: queryパラメータはkeyまたはkey rangeIDBKeyRange)で、 カーソルのrangeとして使います。nullまたは未指定の場合、無制限キー範囲が使われます。

openKeyCursor(query, direction) メソッドの手順は以下の通りです:

  1. transactionthistransactionとする。

  2. indexthisindexとする。

  3. もしindexまたはindexオブジェクトストアが削除されていた場合、 throwし、"InvalidStateError" DOMExceptionとする。

  4. もしtransactionstateactiveでなければ、 throwし、"TransactionInactiveError" DOMExceptionとする。

  5. rangequeryを使って値をキー範囲へ変換するの結果とする。 例外があれば再スローする。

  6. cursorを新しいカーソルとし、 source handlethisに設定し、 positionを未定義にし、 directiondirectionに設定し、 got value flagをfalseにし、 keyvalueを未定義にし、 rangerangeに設定し、 key only flagをtrueに設定する。

  7. operationカーソルを反復処理するアルゴリズム(現在のRealmレコード, cursor)で実行するものとする。

  8. request非同期でリクエストを実行するthisoperationで実行した結果とする。

  9. cursorrequestrequestに設定する。

  10. requestを返す。

注意: queryパラメータはkeyまたはkey rangeIDBKeyRange)で、 カーソルのrangeとして使います。nullまたは未指定の場合、無制限キー範囲が使われます。

4.7. IDBKeyRange インターフェイス

IDBKeyRange インターフェイスは キー範囲を表します。

[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);
};
range . lower

レンジの下限を返します。存在しない場合はundefinedを返します。

range . upper

レンジの上限を返します。存在しない場合はundefinedを返します。

range . lowerOpen

レンジの下限開放フラグを返します。

range . upperOpen

レンジの上限開放フラグを返します。

lowerゲッターの手順は、 キーを値に変換するthis下限に対して呼び出し、nullでなければその結果を、そうでなければundefinedを返します。

upperゲッターの手順は、 キーを値に変換するthis上限に対して呼び出し、nullでなければその結果を、そうでなければundefinedを返します。

lowerOpenゲッターの手順は this下限開放フラグを返します。

upperOpenゲッターの手順は this上限開放フラグを返します。

range = IDBKeyRange . only(key)

新しいIDBKeyRange を作成し、keyのみを範囲に含みます。

range = IDBKeyRange . lowerBound(key [, open = false])

新しいIDBKeyRange を作成し、keyから始まり上限はありません。openがtrueの場合、keyは範囲に含まれません。

range = IDBKeyRange . upperBound(key [, open = false])

新しいIDBKeyRange を作成し、下限はなくkeyまでの範囲となります。openがtrueの場合、keyは範囲に含まれません。

range = IDBKeyRange . bound(lower, upper [, lowerOpen = false [, upperOpen = false]])

新しいIDBKeyRange を作成し、lowerからupperまでの範囲となります。 lowerOpenがtrueの場合、lowerは範囲に含まれません。 upperOpenがtrueの場合、upperは範囲に含まれません。

only(value)メソッドの手順は以下の通りです:

  1. key値をキーに変換するvalueに対して呼び出し、その結果とする。例外があれば再スローする。

  2. もしkeyが「無効な値」または「無効な型」であれば、throwし、"DataError" DOMExceptionとする。

  3. 新しいキー範囲keyのみを含むものとして作成し、返す。

lowerBound(lower, open) メソッドの手順は以下の通りです:

  1. lowerKey値をキーに変換するlowerに対して呼び出し、その結果とする。例外があれば再スローする。

  2. もしlowerKeyが無効なら、throwし、"DataError" DOMExceptionとする。

  3. 新しいキー範囲を作成し、 下限lowerKeyに、 下限開放フラグopenに、 上限をnullに、 上限開放フラグをtrueに設定し、返す。

upperBound(upper, open) メソッドの手順は以下の通りです:

  1. upperKey値をキーに変換するupperに対して呼び出し、その結果とする。例外があれば再スローする。

  2. もしupperKeyが「無効な値」または「無効な型」であれば、throwし、"DataError" DOMExceptionとする。

  3. 新しいキー範囲を作成し、 下限をnullに、 下限開放フラグをtrueに、 上限upperKeyに、 上限開放フラグopenに設定し、返す。

bound(lower, upper, lowerOpen, upperOpen) メソッドの手順は以下の通りです:

  1. lowerKey値をキーに変換するlowerに対して呼び出し、その結果とする。例外があれば再スローする。

  2. もしlowerKeyが「無効な値」または「無効な型」であれば、throwし、"DataError" DOMExceptionとする。

  3. upperKey値をキーに変換するupperに対して呼び出し、その結果とする。例外があれば再スローする。

  4. もしupperKeyが「無効な値」または「無効な型」であれば、throwし、"DataError" DOMExceptionとする。

  5. もしlowerKeyupperKeyより大きい場合、throwし、"DataError" DOMExceptionとする。

  6. 新しいキー範囲を作成し、 下限lowerKeyに、 下限開放フラグlowerOpenに、 上限upperKeyに、 上限開放フラグupperOpenに設定し、返す。

range . includes(key)

keyがレンジに含まれていればtrue、そうでなければfalseを返します。

includes(key)メソッドの手順は以下の通りです:

  1. k値をキーに変換するkeyに対して呼び出し、その結果とする。例外があれば再スローする。

  2. もしkが「無効な値」または「無効な型」であれば、throwし、"DataError" DOMExceptionとする。

  3. kがこのレンジに含まれていればtrue、そうでなければfalseを返す。

4.8. IDBRecord インターフェイス

IDBRecord インターフェイスはレコードスナップショットを表します。

[Exposed=(Window,Worker)]
interface IDBRecord {
  readonly attribute any key;
  readonly attribute any primaryKey;
  readonly attribute any value;
};
record . key

レコードのキーを返します。

record . primaryKey

レコードがインデックスから取得された場合、インデックスの参照オブジェクトストア内でのレコードのキーを返します。

レコードがオブジェクトストアから取得された場合、レコードのキーを返します。これは record.key と同じキーです。

record . value

レコードのを返します。

keyゲッターの手順は、キーを値に変換するthiskeyに対して呼び出した結果を返します。

primaryKeyゲッターの手順は、キーを値に変換するthisprimary keyに対して呼び出した結果を返します。

valueゲッターの手順は、thisを返します。

4.9. IDBCursor インターフェイス

カーソルオブジェクトは IDBCursor インターフェイスを実装します。 ひとつの IDBCursor インスタンスは、あるカーソルを表すものとして常にひとつだけ存在します。同時に利用できるカーソル数の制限はありません。

[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"
};
cursor . source

カーソルが開かれた IDBObjectStore または IDBIndex を返します。

cursor . direction

カーソルの方向 ("next"、 "nextunique"、 "prev"、 "prevunique") を返します。

cursor . key

カーソルのキーを返します。 カーソルが進行中または終了している場合は"InvalidStateError" DOMException がスローされます。

cursor . primaryKey

カーソルの実効キーを返します。 カーソルが進行中または終了している場合は"InvalidStateError" DOMException がスローされます。

cursor . request

このカーソルを取得するために使われたリクエストを返します。

sourceゲッターの手順は、 thissource handleを返します。

注意: source 属性はnullを返したり例外をスローしたりしません。カーソルが現在反復中、終端を超えた、または トランザクションactiveでなくても同じです。

directionゲッターの手順は、 thisdirectionを返します。

keyゲッターの手順は、 カーソルの現在のkeyキーを値に変換するで変換した結果を返します。

注意: key がオブジェクト(例:DateArray)を返す場合、 カーソルのkeyが変更されるまで毎回同じオブジェクトインスタンスが返されます。 このオブジェクトを変更すると、その変更はカーソル値を参照するすべての利用者に見えますが、データベースの内容は変更されません。

primaryKeyゲッターの手順は、 カーソルの現在の実効キーキーを値に変換するで変換した結果を返します。

注意: primaryKey がオブジェクト(例:DateArray)を返す場合、 カーソルの実効キーが変更されるまで毎回同じオブジェクトインスタンスが返されます。 このオブジェクトを変更すると、その変更はカーソル値を参照するすべての利用者に見えますが、データベースの内容は変更されません。

requestゲッターの手順は、 thisrequestを返します。

🚧 request 属性はこの版で新しく追加されました。 Chrome 76、Edge 79、Firefox 77、Safari 15でサポートされています。 🚧
以下のメソッドはカーソルを進めます。 カーソルが進められると、success イベントが、 カーソルが開かれたときに返された同じIDBRequest に対して発火されます。 result は、範囲内にレコードがあれば同じカーソルを、なければundefinedを返します。

カーソルがすでに進行中にこれらのメソッドを呼び出すと、"InvalidStateError" DOMException がスローされます。

以下のメソッドは、トランザクションactiveでない場合、 "TransactionInactiveError" DOMException がスローされます。

cursor . advance(count)

範囲内の次のcountレコードへカーソルを進めます。

cursor . continue()

範囲内の次のレコードへカーソルを進めます。

cursor . continue(key)

範囲内でkeyに一致またはそれ以降のレコードへカーソルを進めます。

cursor . continuePrimaryKey(key, primaryKey)

範囲内でkeyprimaryKeyに一致またはそれ以降のレコードへカーソルを進めます。sourceインデックスでない場合は"InvalidAccessError" DOMException がスローされます。

advance(count)メソッドの手順は以下の通りです:

  1. もしcountが0の場合、throwし、TypeErrorとする。

  2. transactionthistransactionとする。

  3. もしtransactionstateactiveでなければ、 throwし、"TransactionInactiveError" DOMExceptionとする。

  4. もしthissourceまたはeffective object storeが削除されていた場合、 throwし、"InvalidStateError" DOMExceptionとする。

  5. もしthisgot value flagがfalse(カーソルが反復中または終端を超えている場合)なら、 throwし、"InvalidStateError" DOMExceptionとする。

  6. thisgot value flagをfalseに設定する。

  7. requestthisrequestとする。

  8. requestprocessed flagをfalseに設定する。

  9. requestdone flagをfalseに設定する。

  10. operationカーソルを反復処理するアルゴリズム(現在のRealmレコード, this, count)で実行するものとする。

  11. 非同期でリクエストを実行するthissource handle, operation, requestで実行する。

注意: 新しいカーソルデータが読み込まれる前(例:同じonsuccessハンドラ内でadvance() を2回呼ぶなど)にこのメソッドを複数回呼ぶと、 2回目以降は"InvalidStateError" DOMException がスローされます。これはカーソルのgot value flagがfalseになったためです。

continue(key)メソッドの手順は以下の通りです:

  1. transactionthistransactionとする。

  2. もしtransactionstateactiveでなければ、 throwし、"TransactionInactiveError" DOMExceptionとする。

  3. もしthissourceまたは effective object storeが削除されていた場合、 throwし、"InvalidStateError" DOMExceptionとする。

  4. もしthisgot value flagがfalse(カーソルが反復中または終端を超えている場合)なら、 throwし、"InvalidStateError" DOMExceptionとする。

  5. もしkeyが指定されていれば:

    1. r値をキーに変換するkeyに対して呼び出した結果とする。例外があれば再スローする。

    2. もしrが「無効な値」または「無効な型」であれば、throw し、"DataError" DOMExceptionとする。

    3. keyrとする。

    4. もしkeyless thanまたはequal tothisposition、かつthisdirectionが "next" または"nextunique"であれば、 throwし、"DataError" DOMExceptionとする。

    5. もしkeygreater thanまたはequal tothisposition、かつthisdirectionが "prev" または"prevunique"であれば、 throwし、"DataError" DOMExceptionとする。

  6. thisgot value flagをfalseに設定する。

  7. requestthisrequestとする。

  8. requestprocessed flagをfalseに設定する。

  9. requestdone flagをfalseに設定する。

  10. operationカーソルを反復処理するアルゴリズム(現在のRealmレコード, this, key(指定されていれば))で実行するものとする。

  11. 非同期でリクエストを実行するthissource handle, operation, requestで実行する。

注意: 新しいカーソルデータが読み込まれる前(例:同じonsuccessハンドラ内でcontinue() を2回呼ぶなど)にこのメソッドを複数回呼ぶと、 2回目以降は"InvalidStateError" DOMException がスローされます。これはカーソルのgot value flagがfalseになったためです。

continuePrimaryKey(key, primaryKey) メソッドの手順は以下の通りです:

  1. transactionthistransactionとする。

  2. もしtransactionstateactiveでなければ、 throwし、"TransactionInactiveError" DOMExceptionとする。

  3. もしthissourceまたはeffective object storeが削除されていた場合、 throwし、"InvalidStateError" DOMExceptionとする。

  4. もしthissourceインデックスでなければ、 throwし、"InvalidAccessError" DOMExceptionとする。

  5. もしthisdirectionが"next" または"prev"でなければ、 throwし、"InvalidAccessError" DOMExceptionとする。

  6. もしthisgot value flagがfalse(カーソルが反復中または終端を超えている場合)なら、 throwし、"InvalidStateError" DOMExceptionとする。

  7. r値をキーに変換するkeyに対して呼び出した結果とする。例外があれば再スローする。

  8. もしrが「無効な値」または「無効な型」であれば、throwし、"DataError" DOMExceptionとする。

  9. keyrとする。

  10. r値をキーに変換するprimaryKeyに対して呼び出した結果とする。例外があれば再スローする。

  11. もしrが「無効な値」または「無効な型」であれば、throwし、"DataError" DOMExceptionとする。

  12. primaryKeyrとする。

  13. もしkeyless thanthisposition、かつ thisdirectionが"next"であれば、 throwし、"DataError" DOMExceptionとする。

  14. もしkeygreater thanthisposition、かつ thisdirectionが"prev"であれば、 throwし、"DataError" DOMExceptionとする。

  15. もしkeyequal tothisposition、かつ primaryKeyless thanまたはequal tothisobject store position、かつ thisdirectionが"next"であれば、 throwし、"DataError" DOMExceptionとする。

  16. もしkeyequal tothisposition、かつ primaryKeygreater thanまたはequal tothisobject store position、かつ thisdirectionが"prev"であれば、 throwし、"DataError" DOMExceptionとする。

  17. thisgot value flagをfalseに設定する。

  18. requestthisrequestとする。

  19. requestprocessed flagをfalseに設定する。

  20. requestdone flagをfalseに設定する。

  21. operationカーソルを反復処理するアルゴリズム(現在のRealmレコード, this, key, primaryKey)で実行するものとする。

  22. 非同期でリクエストを実行するthissource handle, operation, requestで実行する。

注意: 新しいカーソルデータが読み込まれる前(例:同じonsuccessハンドラ内でcontinuePrimaryKey() を2回呼ぶなど)にこのメソッドを複数回呼ぶと、 2回目以降は"InvalidStateError" DOMException がスローされます。これはカーソルのgot value flagがfalseになったためです。

以下のメソッドは読取専用トランザクション内で呼び出された場合、 "ReadOnlyError" DOMException がスローされ、トランザクションactiveでない場合は "TransactionInactiveError" DOMException がスローされます。
request = cursor . update(value)

カーソルが指しているレコードを新しい値で更新します。

effective object storein-line keysを使用していて キーが変更される場合、 "DataError" DOMException がスローされます。

成功した場合、requestresultレコードキーとなります。

request = cursor . delete()

カーソルが指しているレコードを削除します。

成功した場合、requestresultundefinedとなります。

update(value)メソッドの手順は以下の通りです:

  1. transactionthistransactionとする。

  2. もしtransactionstateactiveでなければ、 throwし、"TransactionInactiveError" DOMExceptionとする。

  3. もしtransaction読取専用トランザクションであれば、 throwし、 "ReadOnlyError" DOMExceptionとする。

  4. もしthissourceまたはeffective object storeが削除されていた場合、 throwし、"InvalidStateError" DOMExceptionとする。

  5. もしthisgot value flagがfalse(カーソルが反復中または終端を超えている場合)なら、 throwし、"InvalidStateError" DOMExceptionとする。

  6. もしthiskey only flagがtrueであれば、 throwし、"InvalidStateError" DOMExceptionとする。

  7. targetRealmをユーザーエージェント定義のRealmとする。

  8. clonetransaction中にtargetRealm内でvalueクローンとする。例外があれば再スローする。

    なぜ値のコピーを作成するのか? 値は保存時に直列化されます。ここでコピーとして扱うことで、この仕様書内の他のアルゴリズムがそれをECMAScript値として扱えますが、実装は動作の違いが観察されなければ最適化できます。
  9. もしthiseffective object storein-line keysを使用している場合:

    1. kpkキー・パスを使って値からキーを抽出するclonekey paththiseffective object store)で実行した結果とする。例外があれば再スローする。

    2. もしkpkが失敗・無効・equal toでない場合 thiseffective keythrowし、 "DataError" DOMExceptionとする。

  10. operationオブジェクトストアにレコードを格納するアルゴリズム(thiseffective object store, clone, thiseffective key, false)で実行するものとする。

  11. 非同期でリクエストを実行するthisoperationで実行した結果(IDBRequest)を返す。

注意: オブジェクトストアにレコードを格納する結果として、 カーソルが移動した後にレコードが削除されていた場合、新しいレコードが作成されます。

delete()メソッドの手順は以下の通りです:

  1. transactionthistransactionとする。

  2. もしtransactionstateactiveでなければ、 throwし、"TransactionInactiveError" DOMExceptionとする。

  3. もしtransaction読取専用トランザクションであれば、 throwし、 "ReadOnlyError" DOMExceptionとする。

  4. もしthissourceまたはeffective object storeが削除されていた場合、 throwし、"InvalidStateError" DOMExceptionとする。

  5. もしthisgot value flagがfalse(カーソルが反復中または終端を超えている場合)なら、 throwし、"InvalidStateError" DOMExceptionとする。

  6. もしthiskey only flagがtrueであれば、 throwし、"InvalidStateError" DOMExceptionとする。

  7. operationオブジェクトストアからレコードを削除するアルゴリズム(thiseffective object store, thiseffective key)で実行するものとする。

  8. 非同期でリクエストを実行するthisoperationで実行した結果(IDBRequest)を返す。

カーソルkey only flag がfalseの場合は IDBCursorWithValue インターフェイスも実装します。

[Exposed=(Window,Worker)]
interface IDBCursorWithValue : IDBCursor {
  readonly attribute any value;
};
cursor . value

カーソルの現在のを返します。

valueゲッターの手順は、 thisの 現在のを返します。

注意: value がオブジェクトを返す場合、カーソルのが変更されるまで毎回同じオブジェクトインスタンスが返されます。 このオブジェクトを変更すると、その変更は値を参照するすべての利用者に見えますが、データベースの内容は変更されません。

4.10. IDBTransaction インターフェイス

トランザクション オブジェクトは次のインターフェイスを実装します:

[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"
};
transaction . objectStoreNames

このトランザクションのスコープ内のオブジェクトストア名のリストを返します。アップグレードトランザクションの場合は、データベース内のすべてのオブジェクトストアです。

transaction . mode

このトランザクションの作成時のモード("readonly" または"readwrite")、アップグレードトランザクションの場合は"versionchange"を返します。

transaction . durability

このトランザクションの作成時の耐久性ヒント(" strict"、 "relaxed" )、または"default"を返します。

transaction . db

このトランザクションの接続を返します。

transaction . error

このトランザクションが中断された場合、理由を示すエラー(DOMException)を返します。

objectStoreNamesゲッターの手順:

  1. namesリストとして、thisオブジェクトストア名のリストを取得する。

  2. namesソート済み名リストを作成した結果(DOMStringList)を返す。

注意: この属性が返すリストの内容自体は変化しませんが、アップグレードトランザクション中は、オブジェクトストアの新規作成や削除により、呼び出しのたびに異なるリストが返されることがあります。

modeゲッターの手順は thismodeを返します。

durabilityゲッターの手順は thisdurability hintを返します。

🚧 durability 属性はこの版で新しく追加されました。 Chrome 82、Edge 82、Firefox 126、Safari 15でサポートされています。 🚧

dbゲッターの手順は thisconnectionに関連付けられたデータベースを返します。

errorゲッターの手順は thiserror(存在しない場合はnull)を返します。

注意: このトランザクションが失敗したリクエストにより中断された場合、 この値はそのリクエストerrorと同じになります。 イベントハンドラ内の未捕捉例外により中断された場合は、"AbortError" DOMExceptionとなります。 コミット時のエラーで中断された場合は、失敗理由(例: QuotaExceededErrorや"ConstraintError"、"UnknownError" DOMException)が反映されます。

transaction . objectStore(name)

このトランザクションスコープ内にある IDBObjectStore を返します。

transaction . abort()

トランザクションを中断します。保留中のリクエストはすべて "AbortError" DOMException で失敗し、データベースへの変更はすべて元に戻されます。

transaction . commit()

トランザクションのコミットを試みます。保留中のリクエストはすべて完了させますが、新しいリクエストは受け付けません。 このメソッドは、保留中のリクエストのsuccess イベントが発火するのを待たずに、通常のコミット処理を開始するために利用できます。

保留中のリクエストが失敗した場合はトランザクションが中断されます(例:制約エラーなど)。成功したリクエストについてはsuccess イベントが発火しますが、イベントハンドラで例外を投げてもトランザクションは中断されません。同様に、失敗したリクエストのerror イベントが発火しても、preventDefault()を呼んでも中断は防げません。

objectStore(name)メソッドの手順:

  1. もしthisstatefinishedであれば、 throwし、"InvalidStateError" DOMExceptionとする。

  2. storethisオブジェクトストアのうち、nameという名前のものとし、存在しなければ throwし、 "NotFoundError" DOMExceptionとする。

  3. storethisを関連付けたオブジェクトストアハンドルを返す。

注意: 同じIDBTransaction インスタンス上で同じ名前でこのメソッドを呼ぶと、同じIDBObjectStore インスタンスが返されます。

注意: 返されるIDBObjectStore インスタンスは このIDBTransaction に固有です。別のIDBTransactionで呼び出すと、別のIDBObjectStore インスタンスが返されます。

abort()メソッドの手順:

  1. もしthisstatecommittingまたはfinishedであれば、 throwし、"InvalidStateError" DOMExceptionとする。

  2. トランザクションを中断するthis, null)を実行する。

commit()メソッドの手順:

  1. もしthisstateactiveでなければ、 throwし、"InvalidStateError" DOMExceptionとする。

  2. トランザクションをコミットするthis)を実行する。

🚧 commit() メソッドはこの版で新しく追加されました。 Chrome 76、Edge 79、Firefox 74、Safari 15でサポートされています。 🚧

注意: 通常、commit()トランザクションに対して呼び出す必要はありません。 トランザクションは、未処理のリクエストがすべて満たされ、新たなリクエストが作成されていない場合に自動的にコミットされます。 この呼び出しは、未処理のリクエストからイベントが発行されるのを待たずに コミット処理を開始するために使用できます。

onabort属性は、イベントハンドラIDL属性であり、 イベントタイプabortです。

oncomplete属性は、イベントハンドラIDL属性であり、 イベントタイプcompleteです。

onerror属性は、イベントハンドラIDL属性であり、 イベントタイプerrorです。

注意: トランザクションが正常に完了したかどうかを判定するには、 トランザクションcomplete イベントを監視してください。success イベントは個々のリクエストに対して発火しますが、 トランザクションはその後でも失敗する場合があります。

5. アルゴリズム

5.1. データベース接続のオープン

データベース接続をオープンするには、storageKey(データベースのオープン要求元)、データベースname、データベースversionrequestを使い、次の手順を実行する:

  1. queuestorageKeynameに対する接続キューとする。

  2. requestqueueに追加する。

  3. queue内のすべての先行リクエストが処理されるまで待機する。

  4. dbstorageKey内でnameというデータベース名前付き)とし、存在しなければnull。

  5. versionが未定義の場合、dbがnullならversionを1、そうでなければdbversionとする。

  6. もし db が null であれば、db を新しいデータベース名前 nameバージョン 0(ゼロ)、および オブジェクトストアなし)として作成してください。 これが何らかの理由で失敗した場合、適切なエラー(例:QuotaExceededError または "UnknownError" DOMException)を返してください。

  7. dbversionversionより大きい場合、 新しい"VersionError" DOMExceptionを返して処理を中断する。

  8. connectiondbへの新しい接続とする。

  9. connectionversionversionに設定する。

  10. dbversionversion未満なら:

    1. openConnectionsdbに関連付けられたすべての接続の集合で、connectionは除外。

    2. openConnectionsの各entryclose pending flagがtrueでないものに対し、 データベースタスクをキューしてversion changeイベント(名前:versionchange)を entrydbversionversionで発火する。

      注意: このイベント発火により、openConnections内の他のオブジェクトの一部が閉じられる場合がある。その場合、すでに閉じられたものにはversionchangeイベントは発火しない。

    3. すべてのイベントが発火されるまで待機する。

    4. openConnections内でまだ閉じられていない接続があれば、 データベースタスクをキューして version changeイベント(名前:blocked)を requestdbversionversionで発火する。

    5. 待機openConnections内のすべての接続closedになるまで。

    6. データベースをアップグレードするconnection, version, request)を実行する。

    7. connectionclosedなら、 新しい"AbortError" DOMExceptionを返して中断する。

    8. requesterrorがセットされていれば、 データベース接続を閉じるconnection)を実行し、 新しい"AbortError" DOMExceptionを返して中断する。

  11. connectionを返す。

5.2. データベース接続のクローズ

データベース接続を閉じるには、connectionオブジェクトと、オプションのforced flagを使い、以下の手順を実行する:

  1. connectionclose pending flagをtrueに設定する。

  2. forced flagがtrueなら、connectionを使って作成された各transactionについて、 トランザクションを中断するtransaction、新しい"AbortError" DOMException)を実行する。

  3. connectionを使って作成されたすべてのトランザクションが完了するまで待機する。完了したらconnectionclosedとなる。

  4. forced flagがtrueなら、イベント発火(名前:close)をconnectionに対して行う。

    注意: close イベントは接続が異常終了した場合(例:storage keyのストレージクリアや破損・I/Oエラーなど)にのみ発火される。 close() を明示的に呼んだ場合はイベントは発火しない。

注意: 接続close pending flagがtrueになると、新しいトランザクションは 接続を使って作成できなくなる。 トランザクション作成メソッドはまずconnectionclose pending flagがtrueかどうかを確認し、trueなら例外を投げる。

注意: 接続が閉じられると、データベースアップグレードデータベース削除の手順(両方待機)をブロック解除できる。これは、指定されたデータベースへの接続がすべて閉じられるまで待機するため。

5.3. データベース削除

データベースを削除するには、storageKey(削除要求元)、データベースnamerequestを使い、次の手順を実行する:

  1. queuestorageKeynameに対する接続キューとする。

  2. requestqueueに追加する。

  3. queue内のすべての先行リクエストが処理されるまで待機する。

  4. dbstorageKey内でnameというデータベース名前付き)とし、存在しなければ0を返す。

  5. openConnectionsdbに関連付けられたすべての接続の集合とする。

  6. openConnectionsの各entryclose pending flagがtrueでないものに対し、 データベースタスクをキューして version changeイベント(名前:versionchange)をentrydbversionとnullで発火する。

    注意: このイベント発火により、openConnections内の他のオブジェクトの一部が閉じられる場合がある。その場合、すでに閉じられたものにはversionchangeイベントは発火しない。

  7. すべてのイベントが発火されるまで待機する。

  8. openConnections内でまだ閉じられていない接続があれば、 データベースタスクをキューして version changeイベント(名前:blocked)を requestdbversionとnullで発火する。

  9. 待機openConnections内のすべての接続closedになるまで。

  10. versiondbversionとする。

  11. dbを削除する。失敗した場合は、適切なエラー(例:QuotaExceededErrorや"UnknownError" DOMException)を返す。

  12. versionを返す。

5.4. トランザクションのコミット

トランザクションをコミットするには、コミット対象transactionに対して以下の手順を実行する:

  1. transactionstatecommittingに設定する。

  2. 以下の手順を並列で実行する:

    1. transactionrequest listのすべての項目がprocessedになるまで待つ。

    2. transactionstatecommittingでなくなったら、これらの手順を終了する。

    3. transactionが行った未処理の変更をデータベースtransactiondurability hintを考慮して書き込む。

    4. 変更書き込み時にデータベースでエラーが発生した場合、 abort a transactiontransactionとエラー型、例:QuotaExceededErrorや"UnknownError" DOMException)を実行し、これらの手順を終了する。

    5. データベースタスクをキューして以下の手順を実行:

      1. transactionアップグレードトランザクションなら、 transactionconnectionに関連付けられたdatabaseupgrade transactionをnullに設定。

      2. transactionstatefinishedに設定。

      3. イベント発火(名前:complete)をtransactionへ。

        注意: このイベントのハンドラで例外が投げられても、トランザクションはすでにコミットされている。 データベースへの書き込みはイベント発火前に行われるため、イベント後にコミット済みとなる。

      4. transactionアップグレードトランザクションなら、 transactionに関連付けられたrequesttransactionをnullに設定する。

5.5. トランザクションの中断

トランザクションを中断するには、中断対象transactionerrorに対して以下の手順を実行する:

  1. transactionstatefinishedなら、この手順を中止。

  2. transactionデータベースに行ったすべての変更を元に戻す。アップグレードトランザクションの場合、オブジェクトストアやインデックスの集合、versionの変更も含む。トランザクション中に作成されたオブジェクトストアインデックスは、他のアルゴリズム上削除されたものとみなす。

  3. transactionアップグレードトランザクションの場合、 アップグレードトランザクションの中断transaction)を実行する。

    注意: この処理でtransactionに関連付けられたconnectionobject store handleindex handleインスタンスの状態も巻き戻される。

  4. transactionstatefinishedに設定。

  5. transactionerrorerrorに設定。

  6. transactionrequest listの各requestについて 非同期リクエスト実行の手順を中断し、 requestprocessed flagをtrueに、 データベースタスクをキューして以下の手順を実行:

    1. requestdone flagをtrueに設定。

    2. requestresultをundefinedに設定。

    3. requesterrorを新しい"AbortError" DOMExceptionに設定。

    4. イベント発火(名前:error)をrequestへ(bubblescancelableはtrueで初期化)。

    注意: この処理で必ずしもerror イベントが発火するとは限らない。例えばコミット時のエラーや、最後のリクエストのみ失敗した場合は発火しないことがある。

  7. データベースタスクをキューして以下の手順を実行:

    1. transactionアップグレードトランザクションなら、 transactionconnectionに関連付けられたdatabaseupgrade transactionをnullに設定。

    2. イベント発火(名前:abort)をtransactionへ(bubblesはtrueで初期化)。

    3. transactionアップグレードトランザクションなら:

      1. requesttransactionに関連付けられたopen requestとする。

      2. requesttransactionをnullに設定。

      3. requestresultをundefinedに設定。

      4. requestprocessed flagをfalseに設定。

      5. requestdone flagをfalseに設定。

5.6. リクエストの非同期実行 request

リクエストを非同期で実行するには、sourceオブジェクト、データベース上で実行するoperation、オプションのrequestを使い、以下の手順を実行する:

これらの手順は、作成されたrequestが属するトランザクション中断された場合、 トランザクションの中断の手順でいつでも中止可能。

  1. transactionsourceに関連付けられたトランザクションとする。

  2. Assert: transactionstateactiveである。

  3. requestが指定されていなければ、新しいrequestsourcerequestsourceとして作成する。

  4. requesttransactionrequest listの末尾に追加する。

  5. 以下の手順を並列で実行する:

    1. requesttransactionrequest listの 未processed項目の先頭になるまで待つ。

    2. operationを実行した結果をresultとする。

    3. resultがエラーで、transactionstatecommittingなら、 トランザクションの中断transaction, result)を実行し、これらの手順を終了する。

    4. resultがエラーの場合、 operationで行ったすべての変更を巻き戻す。

      注意: これはこのリクエストによる変更のみ巻き戻し、トランザクション全体の他の変更は巻き戻さない。

    5. requestprocessed flagをtrueに設定。

    6. データベースタスクをキューして以下の手順を実行:

      1. requesttransactionrequest listから除去。

      2. requestdone flagをtrueに設定。

      3. resultがエラーの場合:

        1. requestresultをundefinedに設定。

        2. requesterrorresultに設定。

        3. エラーイベント発火requestに対して行う。

      4. それ以外の場合:

        1. requestresultresultに設定。

        2. requesterrorをundefinedに設定。

        3. 成功イベント発火requestに対して行う。

  6. requestを返す。

5.7. データベースのアップグレード

データベースをアップグレードするには、connectionconnection)、新しいversionrequestを使い、以下の手順を実行する:

  1. dbconnectiondatabaseとする。

  2. transactionconnectionconnectionとして用いる新しいアップグレードトランザクションとする。

  3. transactionscopeconnectionobject store setに設定する。

  4. dbupgrade transactiontransactionに設定する。

  5. transactionstateinactiveに設定する。

  6. transactionを開始する。

    注意: このトランザクションが完了するまでは、同じデータベースへの他の接続はオープンできない。

  7. old versiondbversionとする。

  8. dbversionversionに設定する。この変更はトランザクションの一部とみなされるため、トランザクションが中断された場合は巻き戻される。

  9. requestprocessed flagをtrueに設定する。

  10. データベースタスクをキューして以下の手順を実行:

    1. requestresultconnectionに設定する。

    2. requesttransactiontransactionに設定する。

    3. requestdone flagをtrueに設定する。

    4. transactionstateactiveに設定する。

    5. didThrowversion changeイベントを発火(名前:upgradeneededrequestold versionversion)の結果とする。

    6. transactionstateactiveなら:

      1. transactionstateinactiveに設定する。

      2. didThrowがtrueなら、トランザクションの中断transaction、新しい"AbortError" DOMException)を実行する。

  11. transactionfinishされるまで待機する。

    注意: トランザクションライフタイム中に呼び出されるアルゴリズム(commit a transactionabort a transactionの手順)は、アップグレードトランザクション固有の手順も含む。

5.8. アップグレードトランザクションの中断

アップグレードトランザクションの中断には、transactionに対して以下の手順を実行する:

注意: この手順はトランザクションの中断で必要に応じて実行され、データベースの関連するオブジェクトストアインデックスの集合、およびversionの変更を巻き戻す。

  1. connectiontransactionconnectionとする。

  2. databaseconnectiondatabaseとする。

  3. connectionversionを、databaseが以前から存在した場合はそのversion、新規作成の場合は0に設定する。

    注意: これはversionプロパティ(IDBDatabaseオブジェクト)を巻き戻す。

  4. connectionobject store setを、databaseが以前から存在した場合はそのオブジェクトストア集合、そうでなければ空集合に設定する。

    注意: これはobjectStoreNamesプロパティ(IDBDatabaseオブジェクト)を巻き戻す。

  5. transactionに関連付けられた各object store handle handle(トランザクション中に作成・削除されたものも含む)について:

    1. handleobject storeがトランザクション中に新規作成されたものでなければ、 handlenamehandleobject storenameに設定する。

    2. handleindex setを、そのobject storeを参照するインデックス集合に設定する。

    注意: これは関連するnameindexNamesプロパティ(IDBObjectStoreオブジェクト)を巻き戻す。

    これはどのように観測可能か? スクリプトはトランザクションが中断された後、IDBTransactionインスタンスのobjectStore()メソッド経由でオブジェクトストアへアクセスできないが、 IDBObjectStoreインスタンスへの参照は保持できるため、 nameindexNamesプロパティを取得できる。
  6. transactionに関連付けられた各index handle handle(トランザクション中に作成・削除されたものも含む)について:

    1. handleindexがトランザクション中に新規作成されたものでなければ、 handlenamehandleindexnameに設定する。

    注意: これは関連するnameプロパティ(IDBIndexオブジェクト)を巻き戻す。

    これはどのように観測可能か? スクリプトはトランザクションが中断された後、IDBObjectStoreインスタンスのindex()メソッド経由でインデックスにアクセスできないが、 IDBIndexインスタンスへの参照は保持できるため、 nameプロパティを取得できる。

注意: name プロパティ(IDBDatabaseインスタンス)は、 中断されたアップグレードトランザクションが新規データベースを作成した場合でも変更されない。

5.9. 成功イベントの発火

成功イベントを発火するには、requestに対して以下の手順を実行する:

  1. eventEventを使い、イベント作成の結果とする。

  2. eventtype属性を"success"に設定する。

  3. eventbubbles およびcancelable属性をfalseに設定する。

  4. transactionrequesttransactionとする。

  5. legacyOutputDidListenersThrowFlagを初期値falseとする。

  6. transactionstateinactiveなら、 transactionstateactiveに設定する。

  7. イベント配送eventrequestlegacyOutputDidListenersThrowFlagで)。

  8. transactionstateactiveなら:

    1. transactionstateinactiveに設定する。

    2. legacyOutputDidListenersThrowFlagがtrueなら、 トランザクションの中断transaction、新しい"AbortError" DOMException)を実行する。

    3. transactionrequest listが空なら、 トランザクションのコミットtransaction)を実行する。

5.10. エラーイベントの発火

エラーイベントを発火するには、requestに対して以下の手順を実行する:

  1. eventEventを使い、イベント作成の結果とする。

  2. eventtype属性を"error"に設定する。

  3. eventbubbles およびcancelable属性をtrueに設定する。

  4. transactionrequesttransactionとする。

  5. legacyOutputDidListenersThrowFlagを初期値falseとする。

  6. transactionstateinactiveなら、 transactionstateactiveに設定する。

  7. イベント配送eventrequestlegacyOutputDidListenersThrowFlagで)。

  8. transactionstateactiveなら:

    1. transactionstateinactiveに設定する。

    2. legacyOutputDidListenersThrowFlagがtrueなら、 トランザクションの中断transaction、新しい"AbortError" DOMException)を実行し、これらの手順を終了する。 この処理はeventcanceled flagがfalseでも行われる。

      注意: エラーイベント発火時に、どれかのイベントハンドラで例外が投げられた場合、transactionerrorプロパティは AbortErrorにセットされる。これはrequesterrorでなくても、preventDefault()が呼ばれなくても同じ。

    3. eventcanceled flagがfalseなら、 トランザクションの中断transactionrequesterror)を実行し、これらの手順を終了する。

    4. transactionrequest listが空なら、 トランザクションのコミットtransaction)を実行する。

5.11. 値のクローン

クローンを作成するには、 valuetargetRealmtransactionを使い、以下の手順を実行する:

  1. Assert: transactionstateactiveである。

  2. transactionstateinactiveに設定する。

    注意: トランザクションinactiveにすることで、 クローン操作によって発生するgetterや他の副作用がトランザクションに対して追加リクエストを行えなくなる。

  3. serialized? StructuredSerializeForStorage(value)の結果とする。

  4. clone? StructuredDeserialize(serializedtargetRealm)の結果とする。

  5. transactionstateactiveに設定する。

  6. cloneを返す。

5.12. 複数アイテム取得リクエストの作成

複数アイテム取得リクエストの作成には、object storeまたはindexから、targetRealmsourceHandlekindqueryOrOptions、オプションのcountを使い、以下の手順を実行する:

  1. sourcesourceHandleから取得したindexまたはobject storeとする。 sourceHandleindex handleの場合はsourceそのindex handleのindex。 それ以外の場合はsourceそのobject store handleのobject store

  2. sourceが削除されていれば、throwし、"InvalidStateError" DOMExceptionとする。

  3. sourceindexで、sourceobject storeが削除されていれば、 throwし、"InvalidStateError" DOMExceptionとする。

  4. transactionsourceHandletransactionとする。

  5. transactionstateactiveでなければ、 throwし、"TransactionInactiveError" DOMExceptionとする。

  6. rangekey rangeとする。

  7. directioncursor directionとする。

  8. is a potentially valid key rangequeryOrOptions)の結果がtrueなら:

    1. range値をキー範囲に変換queryOrOptions)の結果とする。例外は再スロー。

    2. directionを"next"に設定する。

  9. そうでなければ:

    1. range値をキー範囲に変換queryOrOptions["query"])の結果とする。例外は再スロー。

    2. countqueryOrOptions["count"]に設定する。

    3. directionqueryOrOptions["direction"]に設定する。

  10. operationにアルゴリズムを設定する。

  11. sourceindexなら、 operationインデックスから複数アイテム取得targetRealmsourcerangekinddirectioncount)を設定。

  12. そうでなければ、operationオブジェクトストアから複数アイテム取得targetRealmsourcerangekinddirectioncount)を設定。

  13. 非同期リクエスト実行sourceHandleoperation)の結果(IDBRequest)を返す。

注意: rangekeyまたはkey rangeIDBKeyRange)であり、取得対象のrecordアイテムを特定する。nullまたは未指定の場合はunbounded key rangeが使われる。 count指定時、範囲内にcountより多くのレコードがある場合は、最初のcount件のみ取得する。

6. データベース操作

この節では、データベース内のオブジェクトストアインデックスで実行される様々な操作について説明します。 これらの操作は非同期リクエスト実行の手順で実行されます。

注意: 以下の操作手順内で呼び出されるStructuredDeserialize()は、!の接頭辞が示す通り、必ず例外を投げないと断言できます。 これは、必ずStructuredSerializeForStorage()の出力に対してのみ動作するためです。

6.1. オブジェクトストアへの保存操作

オブジェクトストアにレコードを格納するには storevalue、(オプション)keyno-overwrite flagを使い、以下の手順を実行する:

  1. storeキージェネレーターを使用している場合:

    1. keyが未定義なら:

      1. keystoreに対してキー生成の結果とする。

      2. keyが失敗なら、この操作は"ConstraintError" DOMException で失敗とし、以降の手順を全て中止する。

      3. storeインラインキーも使用している場合は、 キーを値へ注入するvaluekeystorekey pathで実行する。

    2. そうでなければ、storeに対してkeyキージェネレーターの更新を行う。

  2. no-overwrite flagが指定されtrueで、かつstorekey等しいキーのレコードが既に存在する場合、この操作は"ConstraintError" DOMException で失敗とし、以降の手順を全て中止する。

  3. storekey等しいキーのレコードが既に存在する場合は、 オブジェクトストアからレコード削除でそのレコードを削除する。

  4. storekeyをキー、StructuredSerializeForStorage(value)を値とするレコードを格納する。レコードはオブジェクトストアのレコードリスト内でキー昇順でソートされて格納される。

  5. storeを参照する各indexについて:

    1. index keyキー・パスで値からキーを抽出するvalueindexkey pathindexmultiEntry flag)の結果とする。

    2. index keyが例外・無効・失敗なら、そのindexについては以降何もせず次のインデックスへ。

      注意: この段階で例外が投げられても再スローされません。

    3. indexmultiEntry flagがfalse、またはindex key配列キーでない場合、かつindexindex key等しいキーのレコードが既に存在し、かつindexunique flagがtrueなら、この操作は"ConstraintError" DOMException で失敗とし、以降の手順を全て中止する。

    4. indexmultiEntry flagがtrue、かつindex key配列キーの場合、indexindex keysubkeysのいずれかと等しいキーのレコードが既に存在し、かつindexunique flagがtrueなら、この操作は"ConstraintError" DOMException で失敗とし、以降の手順を全て中止する。

    5. indexmultiEntry flagがfalse、またはindex key配列キーでない場合は、indexindex keyをキー、keyを値とするレコードを格納する。レコードはインデックスのレコードリスト内でキー→値昇順でソートされる。

    6. indexmultiEntry flagがtrue、かつindex key配列キーの場合は、index keysubkeysそれぞれについて、キー:subkey、値:keyindexにレコードを格納する。レコードはインデックスのレコードリスト内でキー→値昇順でソートされる。

      注意: subkeysが空の場合は、インデックスにレコードは追加されません。

      注意: subkeysの要素が配列キーでも、そのままインデックスレコードのキーとなる。ネストした配列キーはフラット化や展開されない。外側の配列キーのみが使われる。

  6. keyを返す。

6.2. オブジェクトストアの取得操作

オブジェクトストアから値を取得するには targetRealmstorerangeを使い、以下の手順を実行する。 返り値はundefined、ECMAScript値、またはエラー(DOMException):

  1. recordstoreレコードリスト内でrange含まれるキーを持つ最初のレコードとする(存在する場合)。

  2. recordが見つからなければundefinedを返す。

  3. serializedrecordとする。ストレージから値の読み出し時にエラーが発生した場合は、新しい"NotReadableError" DOMExceptionを返す。

  4. StructuredDeserialize(serialized, targetRealm)の結果を返す。

オブジェクトストアからキーを取得する にはstorerangeを使い、以下の手順を実行する:

  1. recordstoreレコードリスト内でrange含まれるキーを持つ最初のレコードとする(存在する場合)。

  2. recordが見つからなければundefinedを返す。

  3. キーを値に変換するrecordのkey)を返す。

オブジェクトストアから複数アイテムを取得する にはtargetRealmstorerangekinddirection、(オプション)countを使い、以下の手順を実行する:

  1. countが未指定または0なら、countを無限大とする。

  2. recordsを空のリストレコード用)とする。

  3. directionが"next"または"nextunique"なら、recordsstoreレコードリスト内でrange含まれるキーを持つ最初のcount件とする。

  4. directionが"prev"または"prevunique"なら、recordsstoreレコードリスト内でrange含まれるキーを持つ最後のcount件とする。

  5. listを空のリストとする。

  6. recordsの各recordについてkindで分岐:

    "key"
    1. キーを値に変換するrecordのkey)をkeyとする。

    2. keylistに追加。

    "value"
    1. serializedrecordとする。

    2. valueStructuredDeserialize(serialized, targetRealm)の結果とする。

    3. valuelistに追加。

    "record"
    1. keyrecordのkeyとする。

    2. serializedrecordとする。

    3. valueStructuredDeserialize(serialized, targetRealm)の結果とする。

    4. recordSnapshotを、keyをキー、valueを値、keyを主キーとして持つ新しいrecord snapshotとする。

    5. recordSnapshotlistに追加。

  7. listを返す。

6.3. インデックス取得操作

インデックスから参照値を取得する にはtargetRealmindexrangeを使い、以下の手順を実行する:

  1. recordindexレコードリスト内でrange含まれるキーを持つ最初のレコードとする(存在する場合)。

  2. recordが見つからなければundefinedを返す。

  3. serializedrecord参照値とする。

  4. StructuredDeserialize(serialized, targetRealm)の結果を返す。

インデックスから値を取得する にはindexrangeを使い、以下の手順を実行する:

  1. recordindexレコードリスト内でrange含まれるキーを持つ最初のレコードとする(存在する場合)。

  2. recordが見つからなければundefinedを返す。

  3. キーを値に変換するrecordの値)を返す。

インデックスから複数アイテムを取得する にはtargetRealmindexrangekinddirection、(オプション)countを使い、以下の手順を実行する:

  1. countが未指定または0なら、countを無限大とする。

  2. recordsを空のリストレコード用)とする。

  3. directionで分岐:

    "next"
    1. recordsindexレコードリスト内でrange含まれるキーを持つ最初のcount件とする。

    "nextunique"
    1. rangeRecordsindexレコードリスト内でrange含まれるキーのリストとする。

    2. rangeRecordsLengthrangeRecordsサイズとする。

    3. iを0とする。

    4. irangeRecordsLength未満の間、以下を実行:

      1. iを1増やす。

      2. recordサイズcountに等しい場合、break

      3. 2つのキーを比較する(|rangeRecords[i]|と|rangeRecords[i-1]|のキーを使用)の結果が等しければ、continue

      4. それ以外はrecordsに|rangeRecords[i]|を追加

    "prev"
    1. recordsindexレコードリスト内でrange含まれるキーを持つ最後のcount件とする。

    "prevunique"
    1. rangeRecordsindexレコードリスト内でrange含まれるキーのリストとする。

    2. rangeRecordsLengthrangeRecordsサイズとする。

    3. iを0とする。

    4. irangeRecordsLength未満の間、以下を実行:

      1. iを1増やす。

      2. recordサイズcountに等しい場合、break

      3. 2つのキーを比較する(|rangeRecords[i]|と|rangeRecords[i-1]|のキーを使用)の結果が等しければ、continue

      4. それ以外は|rangeRecords[i]|をrecords先頭追加

  4. listを空のリストとする。

  5. recordsの各recordについてkindで分岐:

    "key"
    1. キーを値に変換するrecordの値)をkeyとする。

    2. keylistに追加。

    "value"
    1. serializedrecord参照値とする。

    2. valueStructuredDeserialize(serialized, targetRealm)の結果とする。

    3. valuelistに追加。

    "record"
    1. index keyrecordのキーとする。

    2. keyrecordの値とする。

    3. serializedrecord参照値とする。

    4. valueStructuredDeserialize(serialized, targetRealm)の結果とする。

    5. recordSnapshotを、index keyをキー、valueを値、keyを主キーとして持つ新しいrecord snapshotとする。

    6. recordSnapshotlistに追加。

  6. listを返す。

6.4. オブジェクトストア削除操作

オブジェクトストアからレコードを削除する にはstorerangeを使い、以下の手順を実行する:

  1. storeレコードリスト内でrange含まれるキーを持つすべてのレコードを削除する。

  2. storeを参照する各indexについて、range含まれる値を持つindexレコードリスト内のすべてのレコードを削除する(存在する場合)。

  3. undefinedを返す。

6.5. レコード数カウント操作

範囲内レコード数を数えるにはsourcerangeを使い、以下の手順を実行する:

  1. countsourceのレコードリスト内でrange含まれるキーを持つレコードの数(存在する場合)とする。

  2. countを返す。

6.6. オブジェクトストアクリア操作

オブジェクトストアをクリアするにはstoreを使い、以下の手順を実行する:

  1. storeからすべてのレコードを削除する。

  2. storeを参照するすべてのインデックスについて、すべてのレコードを削除する。

  3. undefinedを返す。

6.7. カーソル反復操作

カーソルを反復処理するには、targetRealmcursor、(オプション)keyprimaryKey(反復先)、(オプション)countを使い、以下の手順を実行する:

  1. sourcecursorsourceとする。

  2. directioncursordirectionとする。

  3. AssertprimaryKeyが指定されていれば、sourceindexであり、directionは"next"または"prev"であること。

  4. recordssource内のレコードリストとする。

    注意: recordsは常に昇順キー順でソートされている。 sourceindexの場合、さらに昇順順でセカンダリソートされる(インデックスの値は、参照先レコードキー)。

  5. rangecursorrangeとする。

  6. positioncursorpositionとする。

  7. object store positioncursorobject store positionとする。

  8. countが未指定なら、countを1とする。

  9. countが0より大きい間:

    1. directionで分岐:

      "next"

      found recordrecordsのうち、以下すべてを満たす最初のレコードとする:

      • keyが定義されている場合:

      • primaryKeyが定義されている場合:

      • positionが定義され、sourceobject storeの場合:

        • レコードのキーがpositionより大きい

      • positionが定義され、sourceindexの場合:

        • レコードのキーがposition等しく、値がobject store positionより大きい

        • レコードのキーがpositionより大きい

      • レコードのキーがrange含まれる

      "nextunique"

      found recordrecordsのうち、以下すべてを満たす最初のレコードとする:

      • keyが定義されている場合:

      • positionが定義されている場合:

        • レコードのキーがpositionより大きい

      • レコードのキーがrange含まれる

      "prev"

      found recordrecordsのうち、以下すべてを満たす最後のレコードとする:

      • keyが定義されている場合:

      • primaryKeyが定義されている場合:

      • positionが定義され、sourceobject storeの場合:

        • レコードのキーがpositionより小さい

      • positionが定義され、sourceindexの場合:

        • レコードのキーがposition等しく、値がobject store positionより小さい

        • レコードのキーがpositionより小さい

      • レコードのキーがrange含まれる

      "prevunique"

      temp recordrecordsのうち、以下すべてを満たす最後のレコードとする:

      • keyが定義されている場合:

      • positionが定義されている場合:

        • レコードのキーがpositionより小さい

      • レコードのキーがrange含まれる

      temp recordが定義されていれば、found recordrecordsのうち、temp recordkey等しい最初のレコードとする。

      注意: "prevunique"で反復すると、 "nextunique"と同じレコードを逆順に訪れる。

    2. found recordが未定義なら:

      1. cursorkeyをundefinedに設定。

      2. sourceindexなら、cursorobject store positionをundefinedに設定。

      3. cursorkey only flagがfalseなら、cursorvalueをundefinedに設定。

      4. nullを返す。

    3. positionfound recordのキーとする。

    4. sourceindexなら、object store positionfound recordの値とする。

    5. countを1減らす。

  10. cursorpositionpositionに設定。

  11. sourceindexなら、cursorobject store positionobject store positionに設定。

  12. cursorkeyfound recordのキーに設定。

  13. cursorkey only flagがfalseなら:

    1. serializedを、sourceobject storeならfound recordvalue、 それ以外はfound recordreferenced valueとする。

    2. cursorvalueStructuredDeserialize(serialized, targetRealm)の結果に設定。

  14. cursorgot value flagをtrueに設定。

  15. cursorを返す。

7. ECMAScriptバインディング

この節では、本仕様で定義されたキー値がECMAScript値に変換される方法、 ECMA Script値からキー値への変換方法、 キーパスを使ってECMAScript値から抽出・注入する方法を定義します。 この節はECMAScript言語仕様の型やアルゴリズム、いくつかのアルゴリズム規約を参照します。 [ECMA-262] ここで詳細化されていない変換については[WEBIDL]に定義されています。

7.1. 値からキーを抽出する

キーパスを使って値からキーを抽出する にはvaluekeyPath、(オプション)multiEntry flagを使い、以下の手順を実行します。 これらの手順の結果はキー、invalid、failureのいずれか、あるいは例外を投げる場合があります。

  1. r値上でキーパス評価valuekeyPath)の結果とする。例外は再スロー。

  2. rがfailureなら、failureを返す。

  3. multiEntry flagがfalseなら値からキーへの変換r)の結果を、trueなら値からmultiEntryキーへの変換r)の結果をkeyとする。例外は再スロー。

  4. keyが"invalid value"または"invalid type"なら、invalidを返す。

  5. keyを返す。

値上でキーパス評価にはvaluekeyPathを使い、以下の手順を実行します。結果はECMAScript値またはfailure、あるいは例外を投げる場合があります。

  1. keyPathが文字列のリストなら:

    1. resultを新しいArrayオブジェクト([]と同じ表現で生成)とする。

    2. iを0とする。

    3. keyPathの各itemについて:

      1. keyを再帰的に値上でキーパス評価itemvalue)の結果とする。

      2. Assert: keyabrupt completionではない。

      3. keyがfailureなら、全体のアルゴリズムを中止してfailureを返す。

      4. p! ToString(i)とする。

      5. statusCreateDataProperty(result, p, key)とする。

      6. Assert: statusはtrue。

      7. iを1増やす。

    4. resultを返す。

      注意: この再帰は1段階のみです。キーパスの配列はネストされないためです。

  2. keyPathが空文字列なら、valueを返し、以降の手順はスキップ。

  3. identifiersstrictly splittingkeyPathをU+002E FULL STOPで分割)の結果とする。

  4. identifiersの各identifierについて、該当する分岐へジャンプ:

    もしType(value)がString、かつidentifierが"length"

    valuevalueの要素数に等しいNumberとする。

    valueArrayで、identifierが"length"

    value! ToLength(! Get(value, "length"))とする。

    valueBlobで、identifierが"size"

    valuevaluesizeに等しいNumberとする。

    valueBlobで、identifierが"type"

    valuevaluetypeに等しいStringとする。

    valueFileで、identifierが"name"

    valuevaluenameに等しいStringとする。

    valueFileで、identifierが"lastModified"

    valuevaluelastModifiedに等しいNumberとする。

    その他
    1. Type(value)がObjectでない場合、failureを返す。

    2. hop! HasOwnProperty(value, identifier)とする。

    3. hopがfalseなら、failureを返す。

    4. value! Get(value, identifier)とする。

    5. valueがundefinedなら、failureを返す。

  5. Assert: valueabrupt completionでない。

  6. valueを返す。

注意: 上記手順でAssertionが可能なのは、このアルゴリズムがStructuredDeserializeの出力値のみを扱い、"own"プロパティしか参照しないためです。

7.2. キーを値へ注入する

注意: この節で使われるキーパスは常に文字列で、シーケンスにはなりません。 キージェネレーターを持ち、かつ キーパスが シーケンスであるオブジェクトストアは作成できないためです。

キーが値に注入可能かを確認するにはvaluekeyPathを使い、以下の手順を実行します。 結果はtrueまたはfalseです。

  1. identifiersstrictly splittingkeyPathをU+002E FULL STOPで分割)の結果とする。

  2. Assert: identifiersは空でない。

  3. identifiersの最後のitemを削除する。

  4. identifiersの残りの各identifierについて、もしあれば:

    1. valueObject またはArray でなければfalseを返す。

    2. hop! HasOwnProperty(value, identifier)とする。

    3. hopがfalseならtrueを返す。

    4. value! Get(value, identifier)とする。

  5. valueObject またはArray ならtrueを、そうでなければfalseを返す。

注意: 上記手順でAssertionが可能なのは、このアルゴリズムがStructuredDeserializeの出力値のみを扱うためです。

キーパスを使って値にキーを注入する にはvaluekeykeyPathを使い、以下の手順を実行します:

  1. identifiersstrictly splittingkeyPathをU+002E FULL STOPで分割)の結果とする。

  2. Assert: identifiersは空でない。

  3. lastidentifiersの最後のitemとし、リストから削除する。

  4. identifiersの各identifierについて:

    1. Assert: valueObject またはArray

    2. hop! HasOwnProperty(value, identifier)とする。

    3. hopがfalseなら:

      1. oを新しいObject({})と同じ式で生成)とする。

      2. statusCreateDataProperty(value, identifier, o)とする。

      3. Assert: statusはtrue。

    4. value! Get(value, identifier)とする。

  5. Assert: valueObject またはArray

  6. keyValueキーを値に変換するkey)の結果とする。

  7. statusCreateDataProperty(value, last, keyValue)とする。

  8. Assert: statusはtrue。

注意: 上記手順でAssertionが可能なのは、このアルゴリズムがStructuredDeserializeの出力値のみを扱い、 かつキーが値に注入可能かを確認する手順が実行済みのためです。

7.3. キーを値へ変換する

キーを値に変換するにはkeyを使い、以下の手順を実行します。 ECMAScript値を返します。

  1. typekeytypeとする。

  2. valuekeyvalueとする。

  3. typeで分岐:

    number

    valueに等しいECMAScript Number値を返す。

    string

    valueに等しいECMAScript String値を返す。

    date
    1. dateをECMAScript Dateコンストラクタにvalueを一つだけ引数として渡して実行した結果とする。

    2. Assert: dateabrupt completionではない。

    3. dateを返す。

    binary
    1. lenvalue長さとする。

    2. bufferをECMAScript ArrayBufferコンストラクタにlenを渡して実行した結果とする。

    3. Assert: bufferabrupt completionではない。

    4. bufferの[[ArrayBufferData]]内部スロットの内容をvalueのエントリでセットする。

    5. bufferを返す。

    array
    1. arrayをECMAScript Arrayコンストラクタを引数なしで実行した結果とする。

    2. Assert: arrayabrupt completionではない。

    3. lenvalueサイズとする。

    4. indexを0とする。

    5. indexlen未満の間:

      1. entryキーを値に変換するvalue[index])の結果とする。

      2. statusCreateDataProperty(array, index, entry)とする。

      3. Assert: statusはtrue。

      4. indexを1増やす。

    6. arrayを返す。

7.4. 値をキーへ変換する

値をキーへ変換するには、ECMAScript値inputと(オプション)setseenを使い、以下の手順を実行します。 結果はキー、"invalid value"、"invalid type"、または例外を投げる場合があります。

  1. seenが未指定なら、新しい空のsetとする。

  2. seen含むinputなら、"invalid value"を返す。

  3. 以下の分岐へジャンプ:

    Type(input)がNumberの場合
    1. inputがNaNなら"invalid value"を返す。

    2. それ以外は、キーtype: number, value: input)を返す。

    inputDate([[DateValue]]内部スロットを持つ)場合
    1. msinputの[[DateValue]]内部スロットの値とする。

    2. msがNaNなら"invalid value"を返す。

    3. それ以外は、キーtype: date, value: ms)を返す。

    Type(input)がStringの場合
    1. キーtype: string, value: input)を返す。

    inputbuffer source typeの場合
    1. inputdetachedなら"invalid value"を返す。

    2. bytesバッファソースからバイトコピー取得input)の結果とする。

    3. キーtype: binary, value: bytes)を返す。

    inputArray exotic objectの場合
    1. len? ToLength( ? Get(input, "length"))とする。

    2. Append inputseenへ追加。

    3. keysを新しい空リストとする。

    4. indexを0とする。

    5. indexlen未満の間:

      1. hop? HasOwnProperty(input, index)とする。

      2. hopがfalseなら"invalid value"を返す。

      3. entry? Get(input, index)とする。

      4. key値をキーへ変換するentry, seen)の結果とする。

      5. ReturnIfAbrupt(key)。

      6. keyが"invalid value"または"invalid type"なら、これらの手順を中止し"invalid value"を返す。

      7. keykeysへ追加。

      8. indexを1増やす。

    6. array keyvalue: keys)を返す。

    その他

    "invalid type"を返す。

値をmultiEntryキーへ変換するにはECMAScript値inputを使い、以下の手順を実行します。 結果はキー、"invalid value"、"invalid type"、または例外を投げる場合があります。

  1. inputArray exotic objectなら:

    1. len? ToLength( ? Get(input, "length"))とする。

    2. seeninputのみを含むsetとする。

    3. keysを新しい空のリストとする。

    4. indexを0とする。

    5. indexlen未満の間:

      1. entryGet(input, index)とする。

      2. entryabrupt completionでなければ:

        1. key値をキーへ変換するentry, seen)の結果とする。

        2. keyが"invalid value"、"invalid type"、abrupt completionでなければ、かつkeys内にkey等しいitemがなければ、keykeysへ追加。

      3. indexを1増やす。

    6. array keyvalue: keys)を返す。

  2. それ以外の場合、値をキーへ変換するinput)の結果を返す。例外は再スロー。

注意: これらの手順は値をキーへ変換するの手順と似ていますが、トップレベル値がArrayの場合、キーに変換できないメンバーは無視され、重複は除去されます。

例:値[10, 20, null, 30, 20]は、array keysubkeys: 10, 20, 30)へ変換されます。

8. プライバシーに関する考慮事項

この節は規範的ではありません。

8.1. ユーザーの追跡

サードパーティのホスト(または複数のサイトへコンテンツ配信が可能なオブジェクト)は、クライアントサイドデータベースに一意の識別子を保存することで、ユーザーを複数セッションに渡り追跡し、ユーザーの活動履歴のプロフィールを構築できる。ユーザーの実IDオブジェクトを認識しているサイト(例:認証資格情報を要求するECサイトなど)と組み合わせれば、抑圧的な集団が匿名Web利用の世界よりも高精度に個人をターゲットできる可能性がある。

ユーザー追跡リスクを軽減する技術はいくつかある:

サードパーティストレージのブロック

ユーザーエージェントはデータベースオブジェクトへのアクセスを、閲覧コンテキストのトップレベルドキュメントのドメイン発のスクリプトにのみ制限できる。例えば、他ドメインのiframeページからのAPIアクセスを拒否することができる。

保存データの有効期限設定

ユーザーエージェントは一定期間後に自動で保存データを削除できる。

これにより、サイトはユーザーが認証(例:購入やサービスログイン)した場合のみ複数セッションをまたいだ追跡が可能となり、追跡能力が制限される。

ただし、これによりユーザーのデータが失われるリスクもある。

永続ストレージをクッキー同様に扱う

ユーザーエージェントはデータベース機能をHTTPセッションクッキーと強く関連付けてユーザーに提示すべきである。 [COOKIES]

これにより、ユーザーがこの種のストレージを慎重に扱うよう促されるかもしれない。

サイトごとのデータベースアクセスの許可リスト化

ユーザーエージェントは、サイトがこの機能を利用する前にユーザーの許可を求めるようにできる。

サードパーティストレージへの帰属記録

ユーザーエージェントは、第三者オリジンがデータ保存を引き起こした場合、そのオリジンを記録できる。

この情報を永続ストレージの表示に利用すれば、ユーザーはどのストレージを削除すべきか判断できる。「このドメインのデータを削除し、今後保存を禁止する」などのブロックリストと組み合わせれば、信頼するサイトのみ永続ストレージの利用を許可できる。

共有ブロックリスト

ユーザーエージェントは、ユーザーが永続ストレージのドメインブロックリストを共有できるようにすることができる。

これにより、コミュニティ全体でプライバシー保護を強化できる。

これらの提案はAPIの安易なユーザー追跡利用を防ぐが、完全な防止には至らない。同一ドメイン内では、サイトは引き続きセッション内でユーザーを追跡でき、取得した識別情報(氏名、クレジットカード番号、住所など)と共に第三者へ渡すことも可能である。複数サイトが協力すれば、依然としてプロフィールが作成され得る。

ただし、ユーザーエージェントが協力しなくても、URLのセッション識別子などを使ってユーザー追跡はある程度可能である。この技術は元々無害な用途でも利用されているが、簡単に追跡目的に転用できる。こうした情報は他サイトと共有可能であり、訪問者のIPアドレスやその他のユーザー固有データ(User-Agentヘッダや設定など)を使って複数セッションを統合したユーザープロファイルを作成できる。

永続ストレージのユーザーインターフェースで、現行仕様で説明されている永続ストレージとHTTPセッションクッキーのデータを別々に表示した場合、ユーザーは一方のみを削除してしまう可能性がある。これにより、サイトは両機能を相互バックアップとして利用でき、ユーザーのプライバシー保護の試みを無効化できてしまう。

8.3. データの機微性

ユーザーエージェントは、永続的に保存されたデータを機微なものとして扱うべきである。メール、予定表、健康記録などの機密文書がこの仕組みに保存される可能性がある。

したがって、削除時には速やかに基盤ストレージからデータを消去するよう努めるべきである。

9. セキュリティに関する考慮事項

9.1. DNSスプーフィング攻撃

DNSスプーフィング攻撃の可能性があるため、あるドメインから来たと主張するホストが本当にそのドメイン由来かどうかは保証できない。これへの対策として、ページはTLSを利用できる。TLSを使うページは、同じドメインかつTLS証明書によって識別されたページのみがデータベースへアクセスできることを保証できる。

9.2. ディレクトリ横断攻撃

一つのホスト名を複数の著者が共有する場合(例:geocities.comでコンテンツをホストするユーザー)は、すべて同じデータベースセットを共有する。

パス名によるアクセス制限機能は存在しない。共有ホストの著者は、他の著者がデータを読み取ったり上書きしたりするのが容易なため、これらの機能の利用を避けることを推奨する。

注意: 仮にパス制限機能が導入されたとしても、通常のDOMスクリプトのセキュリティモデルによって、この保護を容易に迂回しどのパスからでもデータにアクセスできてしまう。

9.3. 実装上のリスク

永続ストレージを実装する際の主なリスクは、悪意あるサイトが他ドメインの情報を読み取ること、または他ドメインへ書き込むことができてしまうことである。

第三者サイトが本来アクセスできないデータを読み取ると、情報漏洩が生じる。例えば、一つのドメインのショッピングウィッシュリストが他ドメインのターゲット広告に利用されたり、ワープロサイトが保存していた作業中の機密文書が競合会社のサイトで閲覧されるなどの危険がある。

第三者サイトが他ドメインの永続ストレージに書き込みできてしまうと、情報の偽装も同様に危険である。例えば、悪意サイトがユーザーのウィッシュリストにレコードを追加したり、セッションIDを既知のIDに設定してユーザーの行動を追跡したりできる。

したがって、本仕様で定義されたストレージキー分割モデルを厳守することがユーザーの安全のため重要である。

ホスト名やデータベース名をファイルシステムのパス構築に利用する場合、適切にエスケープ処理を施すべきである。そうしないと、攻撃者が相対パス(例:「../」)を使って他のストレージキーの情報にアクセスできてしまう。

9.4. 永続性のリスク

実際の実装ではデータは不揮発性ストレージへ保存される。データは保存時にシリアライズされ、取得時にデシリアライズされるが、シリアライズ形式の詳細はユーザーエージェント固有である。ユーザーエージェントは時間とともにシリアライズ形式を変更する可能性が高い。例えば新しいデータ型への対応や性能向上のために形式が更新されることがある。本仕様の運用要件を満たすため、実装は古いシリアライズ形式も何らかの方法で扱う必要がある。古いデータの不適切な取り扱いはセキュリティ問題の原因となる。シリアライズされたデータにはユーザーエージェントの新しいバージョンでは有効でない仮定が含まれることもある。

具体例として、RegExp型がある。 StructuredSerializeForStorage操作ではRegExpオブジェクトをシリアライズできる。一般的なユーザーエージェントは正規表現を機械語命令へコンパイルし、入力データの渡し方や結果の返し方に関する仮定が含まれる。内部状態がデータベース保存時にシリアライズされてしまうと、後でデシリアライズした際に様々な問題が生じる。例えば、データの渡し方が変わっていたり、コンパイラ出力のバグがエージェント更新で修正されているのに、シリアライズされた内部状態には残っている場合がある。

ユーザーエージェントは古いデータを適切に識別・処理しなければならない。一つの方法として、シリアライズ形式にバージョン識別子を含め、古いデータが検出された場合はスクリプトから見える状態のみから内部状態を再構築する方法がある。

10. アクセシビリティに関する考慮事項

この節は規範的ではありません。

本仕様で規定されたAPIはアクセシビリティへの考慮事項が限られている:

APIは構造化コンテンツの保存を可能とする。テキストコンテンツは文字列として保存できる。APIには画像や音声といった非テキストコンテンツをBlobFileImageData オブジェクトとして保存できるサポートがある。動的コンテンツアプリケーションの開発者は、様々な技術やニーズを持つユーザーがコンテンツにアクセス可能であることを確保するべきである。

API自体は特定の仕組みを規定しないが、構造化コンテンツの保存は多言語対応など国際化コンテンツの保存も可能にする。異なる言語の代替をレコードやレコード内の構造で保持できる。

APIはユーザーエージェントに対し、APIとの対話を可能とするユーザーインターフェースの生成を義務付けない。ユーザーエージェントはAPIを支援するUI要素を任意で提供できる。例:追加ストレージ容量が必要な場合のユーザープロンプト、特定Webサイトごとのストレージ利用の監視機能、APIストレージ用のレコード閲覧・編集・削除ツールなど。こうしたUIはアクセシビリティ支援技術を考慮して設計すべきである。例えば、グラフィック表示によるストレージ容量使用率を示すUIでは、同じデータをスクリーンリーダーなどの支援ツールにも提供する必要がある。

11. 改訂履歴

この節は規範的ではありません。

以下は、本仕様の前回公開以降の変更点の情報要約です。完全な改訂履歴はこちらで参照できます。 第一版の履歴はこの文書のRevision History、 第二版の履歴はこの文書のRevision Historyを参照してください。

12. 謝辞

この節は規範的ではありません。

第一版の原著者Nikunj Mehta氏、追加編集者Jonas Sicking氏、Eliot Graff氏、Andrei Popescu氏、Jeremy Orlow氏に特別な感謝を表します。

Garret Swart氏は本仕様の設計に非常に大きな影響を与えました。

Bikeshed(本仕様作成に用いた著者ツール)を作成・メンテナンスし、著作全般で助言をいただいたTab Atkins, Jr.氏に感謝します。

特別な感謝を 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, そして Zhiqiang Zhang, 仕様改善につながるフィードバック・提案をくださった皆様に感謝します。

適合性

文書の規約

適合性要件は、記述的な断言とRFC 2119の用語の組み合わせで示されます。 現行標準の規範的な部分で使われる “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, “OPTIONAL” というキーワードは、 RFC 2119で定義されるように解釈されます。 ただし、可読性のため、これらの単語はすべて大文字で記載されません。

本仕様の全ての本文は規範的ですが、明示的に非規範的と記載されている節、例、注記は除きます。[RFC2119]

本仕様の例は「例えば」で始まるか、または class="example" で規範的本文と区別されます。 例:

これは情報提供目的の例です。

情報的な注記は「注記」で始まり、 class="note" で規範的本文と区別されます。 例:

注記:これは情報的な注記です。

適合するアルゴリズム

アルゴリズム内の命令形で表現された要件(例:「先頭の空白文字を除去する」「falseを返してこれらの手順を中止する」など)は、アルゴリズム導入時に用いられるキーワード("must", "should", "may" など)の意味で解釈されます。

アルゴリズムや具体的な手順として表現された適合性要件は、同じ結果となる限り、どのような方法でも実装可能です。 特に、本仕様で定義されるアルゴリズムは理解しやすさを重視しており、性能面は意図していません。 実装者は最適化を推奨します。

索引

本仕様で定義される用語

参照によって定義される用語

参考文献

規範的参考文献

[DOM]
Anne van Kesteren. DOM Standard. 現行標準. URL: https://dom.spec.whatwg.org/
[ECMA-262]
ECMAScript Language Specification. URL: https://tc39.es/ecma262/multipage/
[FileAPI]
Marijn Kruisselbrink. File API. 2024年12月4日. WD. URL: https://www.w3.org/TR/FileAPI/
[HTML]
Anne van Kesteren; 他. HTML Standard. 現行標準. URL: https://html.spec.whatwg.org/multipage/
[INFRA]
Anne van Kesteren; Domenic Denicola. Infra Standard. 現行標準. URL: https://infra.spec.whatwg.org/
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. 1997年3月. Best Current Practice. URL: https://datatracker.ietf.org/doc/html/rfc2119
[STORAGE]
Anne van Kesteren. Storage Standard. 現行標準. URL: https://storage.spec.whatwg.org/
[WEBIDL]
Edgar Chen; Timothy Gu. Web IDL Standard. 現行標準. URL: https://webidl.spec.whatwg.org/

情報的参考文献

[Charmod-Norm]
Addison Phillips; 他. Character Model for the World Wide Web: String Matching. 2021年8月11日. NOTE. URL: https://www.w3.org/TR/charmod-norm/
[COOKIES]
A. Barth. HTTP State Management Mechanism. 2011年4月. Proposed Standard. URL: https://httpwg.org/specs/rfc6265.html
[WEBSTORAGE]
Ian Hickson. Web Storage (Second Edition). 2021年1月28日. REC. URL: https://www.w3.org/TR/webstorage/

IDL索引

[Exposed=(Window,Worker)]
interface IDBRequest : EventTarget {
  readonly attribute any result;
  readonly attribute DOMException? error;
  readonly attribute (IDBObjectStore or IDBIndex or IDBCursor)? source;
  readonly attribute IDBTransaction? transaction;
  readonly attribute IDBRequestReadyState readyState;

  // Event handlers:
  attribute EventHandler onsuccess;
  attribute EventHandler onerror;
};

enum IDBRequestReadyState {
  "pending",
  "done"
};

[Exposed=(Window,Worker)]
interface IDBOpenDBRequest : IDBRequest {
  // Event handlers:
  attribute EventHandler onblocked;
  attribute EventHandler onupgradeneeded;
};

[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;
};

partial interface mixin WindowOrWorkerGlobalScope {
  [SameObject] readonly attribute IDBFactory indexedDB;
};

[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;
};

[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;
};

[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";
};

[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");
};

[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);
};

[Exposed=(Window,Worker)]
interface IDBRecord {
  readonly attribute any key;
  readonly attribute any primaryKey;
  readonly attribute any value;
};

[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"
};

[Exposed=(Window,Worker)]
interface IDBCursorWithValue : IDBCursor {
  readonly attribute any value;
};

[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"
};

MDN

IDBCursor/advance

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBCursor/continue

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBCursor/continuePrimaryKey

In all current engines.

Firefox10+Safari10.1+Chrome58+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android51+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBCursor/delete

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBCursor/direction

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBCursor/key

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBCursor/primaryKey

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBCursor/request

In all current engines.

Firefox77+Safari15+Chrome76+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBCursor/source

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBCursor/update

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBCursor

In all current engines.

Firefox16+Safari8+Chrome24+
Opera44+Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView4.4+Samsung Internet?Opera Mobile43+
MDN

IDBCursorWithValue/value

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBCursorWithValue

In all current engines.

Firefox16+Safari8+Chrome24+
Opera15+Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView4.4+Samsung Internet?Opera Mobile14+
MDN

IDBDatabase/close

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBDatabase/close_event

In all current engines.

Firefox50+Safari10.1+Chrome30+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView37+Samsung Internet?Opera Mobile?
MDN

IDBDatabase/close_event

In all current engines.

Firefox50+Safari10.1+Chrome30+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView37+Samsung Internet?Opera Mobile?
MDN

IDBDatabase/createObjectStore

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBDatabase/deleteObjectStore

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBDatabase/name

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBDatabase/objectStoreNames

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBDatabase/transaction

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBDatabase/version

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBDatabase/versionchange_event

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBDatabase/versionchange_event

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBDatabase

In all current engines.

Firefox16+Safari8+Chrome24+
Opera15+Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView4.4+Samsung Internet?Opera Mobile14+
MDN

IDBFactory/cmp

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBFactory/databases

FirefoxNoneSafari14+Chrome72+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBFactory/deleteDatabase

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBFactory/open

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBFactory

In all current engines.

Firefox16+Safari8+Chrome24+
Opera15+Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView4.4+Samsung Internet?Opera Mobile14+
MDN

IDBIndex/count

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBIndex/get

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBIndex/getAll

In all current engines.

Firefox44+Safari10.1+Chrome48+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBIndex/getAllKeys

In all current engines.

Firefox44+Safari10.1+Chrome48+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBIndex/getKey

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBIndex/keyPath

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBIndex/multiEntry

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBIndex/name

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBIndex/objectStore

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBIndex/openCursor

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBIndex/openKeyCursor

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBIndex/unique

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBIndex

In all current engines.

Firefox16+Safari8+Chrome24+
Opera15+Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView4.4+Samsung Internet?Opera Mobile14+
MDN

IDBKeyRange/bound_static

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBKeyRange/includes

In all current engines.

Firefox47+Safari10.1+Chrome52+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBKeyRange/lower

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBKeyRange/lowerBound_static

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBKeyRange/lowerOpen

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBKeyRange/only_static

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBKeyRange/upper

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBKeyRange/upperBound_static

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBKeyRange/upperOpen

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBKeyRange

In all current engines.

Firefox16+Safari8+Chrome24+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView4.4+Samsung Internet?Opera Mobile14+
MDN

IDBObjectStore/add

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBObjectStore/autoIncrement

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)?IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBObjectStore/clear

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBObjectStore/count

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBObjectStore/createIndex

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBObjectStore/delete

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBObjectStore/deleteIndex

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBObjectStore/get

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBObjectStore/getAll

In all current engines.

Firefox44+Safari10.1+Chrome48+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android48+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBObjectStore/getAllKeys

In all current engines.

Firefox44+Safari10.1+Chrome48+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android48+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBObjectStore/getKey

In all current engines.

Firefox51+Safari10.1+Chrome48+
Opera45+Edge79+
Edge (Legacy)?IENone
Firefox for Android58+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile43+
MDN

IDBObjectStore/index

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBObjectStore/indexNames

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBObjectStore/keyPath

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBObjectStore/name

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBObjectStore/openCursor

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBObjectStore/openKeyCursor

In all current engines.

Firefox44+Safari10.1+Chrome23+
Opera?Edge79+
Edge (Legacy)?IE10+
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBObjectStore/put

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBObjectStore/transaction

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBObjectStore

In all current engines.

Firefox16+Safari8+Chrome24+
Opera15+Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView4.4+Samsung Internet?Opera Mobile14+
MDN

IDBOpenDBRequest/blocked_event

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBOpenDBRequest/upgradeneeded_event

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBOpenDBRequest

In all current engines.

Firefox16+Safari8+Chrome24+
Opera15+Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView4.4+Samsung Internet?Opera Mobile14+
MDN

IDBRequest/error

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBRequest/error_event

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?

IDBTransaction/error_event

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBRequest/readyState

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBRequest/result

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBRequest/source

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBRequest/success_event

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBRequest/transaction

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBRequest

In all current engines.

Firefox16+Safari8+Chrome24+
Opera15+Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android25+Android WebView4.4+Samsung Internet?Opera Mobile14+
MDN

IDBTransaction/abort

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBTransaction/abort_event

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBTransaction/commit

In all current engines.

Firefox74+Safari15+Chrome76+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBTransaction/complete_event

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBTransaction/db

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBTransaction/durability

FirefoxNoneSafari15+Chrome83+
Opera70+Edge83+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBTransaction/error

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBTransaction/mode

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBTransaction/objectStore

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBTransaction/objectStoreNames

In all current engines.

Firefox10+Safari10.1+Chrome48+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBTransaction

In all current engines.

Firefox16+Safari8+Chrome24+
Opera15+Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView4.4+Samsung Internet?Opera Mobile14+
MDN

IDBVersionChangeEvent/IDBVersionChangeEvent

In all current engines.

Firefox25+Safari10+Chrome41+
Opera?Edge79+
Edge (Legacy)?IENone
Firefox for Android?iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBVersionChangeEvent/newVersion

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBVersionChangeEvent/oldVersion

In all current engines.

Firefox10+Safari8+Chrome23+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?
MDN

IDBVersionChangeEvent

In all current engines.

Firefox16+Safari8+Chrome24+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView4.4+Samsung Internet?Opera Mobile?
MDN

indexedDB

In all current engines.

Firefox16+Safari8+Chrome24+
Opera?Edge79+
Edge (Legacy)12+IE10+
Firefox for Android22+iOS Safari?Chrome for Android?Android WebView?Samsung Internet?Opera Mobile?