인덱스드 데이터베이스 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 및 회원의 승인이나 지지를 의미하지는 않습니다.

이 문서는 초안이며 언제든지 업데이트, 교체 또는 폐기될 수 있습니다. 진행 중인 작업 이상의 목적으로 이 문서를 인용하는 것은 부적절합니다.

이 문서는 W3C 특허 정책에 따라 운영되는 그룹에서 작성되었습니다. W3C는 그룹 산출물과 관련된 공개 특허 공개 목록을 유지하고 있으며, 해당 페이지에는 특허 공개 방법에 대한 안내도 포함되어 있습니다. 특정인이 필수 청구항이 포함된 특허를 실제로 알고 있다고 판단할 경우 W3C 특허 정책 6장에 따라 정보를 공개해야 합니다.

이 문서는 2023년 11월 3일 W3C 프로세스 문서에 의해 관리됩니다.

이 문서는 인덱스드 데이터베이스 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. 소개

사용자 에이전트는 웹 애플리케이션의 오프라인 데이터 요구를 충족시키기 위해 많은 수의 객체를 로컬에 저장할 필요가 있습니다. [WEBSTORAGE] 는 키와 그에 해당하는 값의 쌍을 저장하는 데 유용합니다. 하지만, 키의 순차적 조회, 값에 대한 효율적인 검색, 또는 하나의 키에 대해 중복 값을 저장하는 기능은 제공하지 않습니다.

이 명세는 대부분의 고도화된 쿼리 처리기의 핵심인 고급 키-값 데이터 관리를 수행할 수 있는 구체적인 API를 제공합니다. 트랜잭션 데이터베이스를 사용하여 키와 그에 해당하는 값(키당 하나 이상)을 저장하고, 키를 결정적인 순서로 순회할 수 있는 방법을 제공합니다. 이는 보통 삽입, 삭제, 매우 많은 데이터 레코드의 순차적 조회에 효율적인 영속적인 B-트리 데이터 구조를 이용해 구현됩니다.

다음 예제는 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에서는 잡지에 대한 새로운 오브젝트 스토어와 두 개의 인덱스를 추가합니다.
    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();
      // 리로드하면 데이터베이스가 닫히고, 새 자바스크립트와 데이터베이스 정의로 다시 로드됩니다.
    } 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문자열로, DOMString과 동등합니다. 즉, 길이에 상관없는 임의의 16비트 코드 단위 시퀀스이며, 빈 문자열도 포함됩니다. name들은 항상 불투명한 16비트 코드 단위 시퀀스로 비교됩니다.

참고: 그 결과, name 비교는 대소문자뿐만 아니라 정규화 형식, 제어 문자 포함/생략, 기타 유니코드 텍스트의 미세한 차이에 민감합니다. [Charmod-Norm]

구현체가 임의의 문자열을 지원하지 않는 저장 메커니즘을 사용하는 경우, 제공된 name을 저장할 수 있는 문자열로 매핑하기 위해 이스케이프 메커니즘 등을 사용할 수 있습니다.

names names에서 정렬된 name 목록 생성을 하려면 다음 절차를 실행합니다:

  1. sortednames오름차순 정렬로, code unit less than 알고리즘을 사용하여 만듭니다.

  2. sorted에 연결된 새로운 DOMStringList를 반환합니다.

자세히 보기 이는 sort() 메서드를 ArrayString에 적용한 결과와 같습니다. 이 정렬은 각 문자열의 16비트 코드 단위를 비교하여 매우 효율적이고 일관적이며 결정적인 정렬 순서를 만듭니다. 결과 목록은 특정 알파벳이나 사전적 순서와 일치하지 않으며, 특히 서러게이트 페어로 표현된 코드 포인트에 대해서는 더욱 그렇습니다.

2.1. 데이터베이스

storage key는 연관된 database 집합을 가집니다. database는 0개 이상의 오브젝트 스토어를 가지며, 데이터베이스에 저장된 데이터를 보관합니다.

database는 특정 storage key 내에서 식별되는 name을 가집니다. name은 name이며, 데이터베이스의 생명주기 동안 변하지 않습니다.

databaseversion을 가집니다. 데이터베이스가 처음 생성될 때 version은 0(영)입니다.

참고:database는 한 번에 하나의 버전만 가집니다; database가 여러 버전으로 동시에 존재할 수 없습니다. 버전을 변경하는 유일한 방법은 업그레이드 트랜잭션을 사용하는 것입니다.

database는 최대 하나의 업그레이드 트랜잭션이 연관될 수 있으며, 이는 null 또는 업그레이드 트랜잭션입니다. 처음에는 null입니다.

2.1.1. 데이터베이스 연결

스크립트는 database에 직접적으로 상호작용하지 않습니다. 대신, 스크립트는 connection을 통해 간접적으로 접근합니다. connection 오브젝트는 해당 database의 객체들을 조작할 수 있습니다. 또한 트랜잭션을 획득하는 유일한 방법입니다. database에 대해 트랜잭션을 얻으려면 connection을 사용해야 합니다.

database를 열면 connection이 생성됩니다. 하나의 database에 여러 connection이 동시에 존재할 수 있습니다.

connection은 해당 글로벌 스코프에서 열린 connectionstorage key와 연관된 database에만 접근할 수 있습니다.

참고: 이는 Documentdomain 변경에는 영향을 받지 않습니다.

connectionversion을 가지며, connection이 생성될 때 설정됩니다. connection의 생명주기 동안 변화하지 않습니다. 단, 업그레이드가 중단되면 이전 database 버전으로 설정됩니다. connection이 닫히면 version은 더 이상 변경되지 않습니다.

각 connection에는 close pending flag가 있으며, 처음에는 false입니다.

connection이 처음 생성되면 열린 상태입니다. 연결은 여러 방법으로 닫힘 상태가 될 수 있습니다. connection이 생성된 실행 컨텍스트가 파괴될 경우(예: 사용자가 해당 페이지를 벗어남), 연결이 닫힙니다. 명시적으로 데이터베이스 연결 닫기 단계로도 닫을 수 있습니다. 연결이 닫히면 close pending flag는 이미 true가 아니었다면 항상 true로 설정됩니다.

connection은 예외적인 상황(예: 파일 시스템 접근 손실, 권한 변경, storage key 저장소 삭제 등)에서 user agent에 의해 닫힐 수 있습니다. 이 경우 user agent는 데이터베이스 연결 닫기 절차를 해당 connection강제 플래그를 true로 설정하여 실행해야 합니다.

connectionobject store 집합을 가지며, 이는 connection이 생성될 때 연관된 database오브젝트 스토어 집합으로 초기화됩니다. 집합의 내용은 업그레이드 트랜잭션live 상태일 때만 변경됩니다.

connectionget the parent 알고리즘은 null을 반환합니다.

IDBDatabase의 열린 connection에서 versionchange 유형의 이벤트가, 데이터베이스를 업그레이드하거나 삭제하려는 시도가 있을 때 발생합니다. 이 이벤트를 통해 connection이 닫혀 업그레이드나 삭제가 진행될 수 있도록 합니다.

IDBDatabase의 connection에서 close 유형의 이벤트가, 연결이 비정상적으로 닫힘 상태가 될 때 발생합니다.

2.2. 오브젝트 스토어

오브젝트 스토어데이터베이스에 데이터를 저장하기 위한 기본 저장 메커니즘입니다.

각 데이터베이스는 오브젝트 스토어 집합을 가집니다. 오브젝트 스토어 집합은 변경될 수 있지만, 업그레이드 트랜잭션을 통해서만 변경할 수 있습니다. 즉, upgradeneeded 이벤트에 응답하여 변경됩니다. 새로운 데이터베이스가 생성되면 오브젝트 스토어는 포함되어 있지 않습니다.

오브젝트 스토어레코드 목록을 가지며, 오브젝트 스토어에 저장된 데이터를 보관합니다. 각 레코드으로 구성됩니다. 목록은 키에 따라 오름차순으로 정렬됩니다. 하나의 오브젝트 스토어에 동일한 키를 가진 레코드가 여러 개 존재할 수 없습니다.

오브젝트 스토어name을 가지며, 이는 name입니다. 언제나 해당 데이터베이스 내에서 고유합니다.

오브젝트 스토어는 선택적으로 키 경로를 가질 수 있습니다. 오브젝트 스토어가 키 경로를 가지면 인라인 키를 사용한다고 하며, 그렇지 않으면 아웃라인 키를 사용한다고 합니다.

오브젝트 스토어는 선택적으로 키 생성기를 가질 수 있습니다.

오브젝트 스토어는 레코드를 세 가지 소스 중 하나에서 파생할 수 있습니다:

  1. 키 생성기. 키 생성기는 키가 필요할 때마다 단조 증가하는 숫자를 생성합니다.

  2. 키 경로를 통해 키를 파생할 수 있습니다.

  3. 값을 오브젝트 스토어에 저장할 때 명시적으로 키를 지정할 수도 있습니다.

2.2.1. 오브젝트 스토어 핸들

스크립트는 오브젝트 스토어에 직접적으로 상호작용하지 않습니다. 대신, 트랜잭션 내에서, 스크립트는 오브젝트 스토어 핸들을 통해 간접적으로 접근합니다.

오브젝트 스토어 핸들은 연관된 오브젝트 스토어 와 연관된 트랜잭션을 가집니다. 여러 핸들이 서로 다른 트랜잭션에서 동일한 오브젝트 스토어와 연관될 수 있지만, 하나의 트랜잭션 내에서 특정 오브젝트 스토어에 연관된 오브젝트 스토어 핸들은 반드시 하나여야 합니다.

오브젝트 스토어 핸들인덱스 집합을 가집니다. 이는 핸들이 생성될 때 연관된 오브젝트 스토어를 참조하는 인덱스 집합으로 초기화됩니다. 집합의 내용은 업그레이드 트랜잭션live 상태일 때만 변경됩니다.

오브젝트 스토어 핸들name을 가지며, 핸들이 생성될 때 연관된 오브젝트 스토어name으로 초기화됩니다. 이름은 업그레이드 트랜잭션live 상태일 때만 변경될 수 있습니다.

2.3.

각 레코드는 과 연관됩니다. 사용자 에이전트는 모든 직렬화 가능한 객체를 지원해야 합니다. 여기에는 String 원시 값과 Date 객체, ObjectArray 인스턴스, File 객체, Blob 객체, ImageData 객체 등이 포함됩니다. 레코드 은 참조가 아니라 값 자체로 저장 및 조회됩니다. 이후 값의 변경은 데이터베이스에 저장된 레코드에 영향을 주지 않습니다.

레코드 Records이며, StructuredSerializeForStorage 연산의 출력입니다.

2.4.

인덱싱된 데이터베이스에 저장된 레코드를 효율적으로 조회하기 위해, 각 레코드는 자신의 를 기준으로 정렬됩니다.

는 연관된 타입을 가지며, 다음 중 하나입니다: number, date, string, binary, array.

에는 연관된 도 있으며, 이는 타입에 따라 다음 중 하나입니다: 타입이 number 또는 date이면 unrestricted double, 타입이 string이면 DOMString, 타입이 binary이면 바이트 시퀀스, 타입이 array이면 다른 리스트입니다.

ECMAScript [ECMA-262] 값은 값을 키로 변환하는 절차를 따라 로 변환할 수 있습니다.

참고: 다음 ECMAScript 타입은 유효한 키입니다:

다른 ECMAScript 값을 로 변환하려고 하면 실패합니다.

배열 키타입array인 것입니다. 하위 키배열 키항목이며, 배열 키입니다.

두 키 비교 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. Assert: tbdate이다.

    9. -1을 반환한다.

  4. vaa으로 한다.

  5. vbb으로 한다.

  6. ta에 따라 분기한다:

    number
    date
    1. vavb보다 크면 1을 반환한다.

    2. vavb보다 작으면 -1을 반환한다.

    3. 0을 반환한다.

    string
    1. vacode unit less than vb이면 -1을 반환한다.

    2. vbcode unit less than va이면 1을 반환한다.

    3. 0을 반환한다.

    binary
    1. vabyte less than vb이면 -1을 반환한다.

    2. vbbyte less than va이면 1을 반환한다.

    3. 0을 반환한다.

    array
    1. lengthva크기vb크기 중 더 작은 것으로 한다.

    2. i를 0으로 한다.

    3. ilength보다 작은 동안:

      1. cva[i]와 vb[i]를 사용하여 재귀적으로 두 키 비교의 결과로 한다.

      2. c가 0이 아니면 c를 반환한다.

      3. i를 1 증가시킨다.

    4. va크기vb크기보다 크면 1을 반환한다.

    5. va크기vb크기보다 작으면 -1을 반환한다.

    6. 0을 반환한다.

a b보다 크다는 것은 두 키 비교 결과가 1일 때입니다.

a b보다 작다는 것은 두 키 비교 결과가 -1일 때입니다.

a b같다는 것은 두 키 비교 결과가 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인 레코드가 포함됩니다.

인덱스의 레코드는 참조 값을 가진다고 합니다. 이는 인덱스의 참조된 오브젝트 스토어에서 인덱스 레코드의 값과 동일한 키를 가진 레코드의 값입니다. 위 예시에서, 인덱스의 키 keyY이고 값이 X인 레코드는 참조 값A입니다.

앞의 예에서, 인덱스에서 키가 "Alice"이고 값이 123인 레코드는 참조 값{ name: "Alice", title: "CEO" }입니다.

참고: 인덱스의 각 레코드는 인덱스의 참조된 오브젝트 스토어의 단 하나의 레코드만 참조합니다. 하지만 인덱스에는 한 오브젝트 스토어의 동일한 레코드를 참조하는 여러 레코드가 있을 수 있으며, 오브젝트 스토어의 특정 레코드를 참조하는 인덱스 레코드가 없을 수도 있습니다.

인덱스의 레코드는 항상 레코드의 키에 따라 정렬됩니다. 하지만 오브젝트 스토어와 달리, 하나의 인덱스에 동일한 키를 가진 여러 레코드가 있을 수 있습니다. 이러한 레코드는 추가로 인덱스의 레코드의 값(즉, 참조된 오브젝트 스토어의 레코드의 키)에 따라 정렬됩니다.

인덱스name을 가지며, 이는 name입니다. 언제나 인덱스의 참조된 오브젝트 스토어 내에서 고유합니다.

인덱스unique 플래그를 가집니다. true일 경우, 인덱스는 동일한 키를 가진 두 레코드가 존재하지 않도록 보장합니다. 만약 인덱스의 참조 오브젝트 스토어에 인덱스의 키 경로를 평가한 결과가 이미 인덱스에 존재하는 값으로 삽입 또는 갱신하려고 하면, 오브젝트 스토어의 변경 시도가 실패합니다.

인덱스multiEntry 플래그를 가집니다. 이 플래그는 인덱스의 키 경로를 평가한 결과가 배열 키일 때 인덱스의 동작에 영향을 줍니다. multiEntry 플래그가 false이면, 배열 키인 하나의 레코드가 인덱스에 추가됩니다. multiEntry 플래그가 true이면, 하위 키 각각에 대해 하나의 레코드가 인덱스에 추가됩니다.

2.6.1. 인덱스 핸들

스크립트는 인덱스에 직접적으로 상호작용하지 않습니다. 대신, 트랜잭션 내에서 스크립트는 인덱스 핸들을 통해 간접적으로 접근합니다.

인덱스 핸들은 연관된 인덱스 및 연관된 오브젝트 스토어 핸들을 가집니다. 인덱스 핸들트랜잭션 은 연관된 오브젝트 스토어 핸들의 트랜잭션입니다. 여러 핸들이 서로 다른 트랜잭션에서 동일한 인덱스와 연관될 수 있지만, 하나의 트랜잭션 내에서 특정 인덱스에 연관된 인덱스 핸들은 반드시 하나여야 합니다.

인덱스 핸들name을 가지며, 핸들이 생성될 때 연관된 인덱스name으로 초기화됩니다. 이름은 업그레이드 트랜잭션live 상태일 때만 변경될 수 있습니다.

2.7. 트랜잭션

트랜잭션데이터베이스의 데이터와 상호작용하는 데 사용됩니다. 데이터베이스에 데이터를 읽거나 쓰는 모든 작업은 트랜잭션을 통해 이루어집니다.

트랜잭션은 애플리케이션 및 시스템 오류로부터 일부 보호를 제공합니다. 트랜잭션은 여러 데이터 레코드를 저장하거나 특정 데이터 레코드를 조건부로 수정하는 데 사용할 수 있습니다. 트랜잭션은 원자적이고 영속적인 데이터 접근 및 변이 작업 집합을 나타냅니다.

모든 트랜잭션은 connection을 통해 생성되며, 이는 트랜잭션의 connection입니다.

트랜잭션scope를 가지며, 이는 트랜잭션이 상호작용할 수 있는 오브젝트 스토어의 집합입니다.

참고: 트랜잭션scope트랜잭션업그레이드 트랜잭션이 아닌 이상 고정되어 있습니다.

트랜잭션scope가 겹침 상태일 수 있으며, 이는 두 트랜잭션의 오브젝트 스토어가 모두 scope에 포함되어 있을 때입니다.

트랜잭션mode를 가지며, 이는 해당 트랜잭션에서 수행할 수 있는 상호작용 유형을 결정합니다. mode는 트랜잭션이 생성될 때 설정되며, 트랜잭션의 생명주기 동안 고정되어 있습니다. 트랜잭션mode는 다음 중 하나입니다:

"readonly"

이 트랜잭션은 데이터 읽기만 허용됩니다. 이 유형의 트랜잭션에서는 데이터를 수정할 수 없습니다. 이 점 덕분에 읽기 전용 트랜잭션 여러 개가 동시에 시작될 수 있는데, scope겹치는 경우(즉, 동일한 오브젝트 스토어를 사용할 때)에도 가능합니다. 이 유형의 트랜잭션은 데이터베이스가 열린 후 언제든 생성할 수 있습니다.

"readwrite"

이 트랜잭션은 기존 오브젝트 스토어에서 데이터 읽기, 수정, 삭제가 모두 가능합니다. 하지만 오브젝트 스토어나 인덱스를 추가하거나 삭제할 수는 없습니다. "readwrite" 트랜잭션 여러 개는 동시에 시작될 수 없는데, 그 이유는 scope겹치는 경우 서로의 데이터를 트랜잭션 중간에 수정할 수 있기 때문입니다. 이 유형의 트랜잭션은 데이터베이스가 열린 후 언제든 생성할 수 있습니다.

"versionchange"

이 트랜잭션은 기존 오브젝트 스토어에서 데이터 읽기, 수정, 삭제뿐만 아니라 오브젝트 스토어와 인덱스를 추가 및 삭제할 수 있습니다. 이를 수행할 수 있는 유일한 트랜잭션 유형입니다. 이 트랜잭션은 수동으로 생성할 수 없으며, upgradeneeded 이벤트가 발생할 때 자동으로 생성됩니다.

트랜잭션durability hint를 가질 수 있습니다. 이는 트랜잭션 커밋 시 성능과 내구성 중 어느 쪽을 우선할지에 대한 사용자 에이전트에 대한 힌트입니다. durability hint는 다음 중 하나입니다:

"strict"

사용자 에이전트는 모든 미처리 변경사항이 영속적인 저장 매체에 성공적으로 기록된 것을 확인한 후에야 트랜잭션커밋에 성공했다고 판단할 수 있습니다.

"relaxed"

사용자 에이전트는 모든 미처리 변경사항이 운영체제에 기록된 직후 추가적인 검증 없이 트랜잭션커밋에 성공했다고 판단할 수 있습니다.

"default"

사용자 에이전트는 storage bucket에 대한 기본 내구성 동작을 사용해야 합니다. 별도 지정이 없는 한 트랜잭션의 기본값입니다.

참고: 일반적인 구현에서 "strict" 는 사용자 에이전트가 운영체제 I/O 버퍼를 플러시하도록 힌트를 주는 역할을 하며, complete 이벤트가 발생하기 전에 플러시가 수행됩니다. 이는 운영체제 충돌이나 전원 손실 시 변경사항이 영속적으로 저장될 가능성을 높여주지만, 버퍼 플러싱은 상당한 시간이 소요될 수 있고 휴대기기에서는 배터리 소모가 큽니다.

웹 애플리케이션에서는 캐시나 자주 변경되는 데이터 등 일시적인 데이터에는 "relaxed"를 사용하고, 데이터 손실 위험을 최소화하는 것이 성능·전력 소비보다 더 중요한 경우에는 "strict"를 사용하는 것이 권장됩니다. 구현체는 애플리케이션의 durability hint와 사용자 및 기기에 미칠 영향을 함께 고려해야 합니다.

트랜잭션은 선택적으로 cleanup event loop를 가지며, 이는 이벤트 루프입니다.

트랜잭션요청 목록을 가지며, 이는 해당 트랜잭션에 대해 이루어진 대기 중인 요청의 집합입니다.

트랜잭션error를 가지며, 트랜잭션중단될 때 설정됩니다.

참고: 구현자는 값이 "null"인 경우에도 오류로 간주해야 하며, 이는 abort() 에 의해 설정됩니다.

트랜잭션get the parent 알고리즘은 해당 트랜잭션의 connection을 반환합니다.

읽기 전용 트랜잭션트랜잭션mode가 "readonly"인 것입니다.

읽기/쓰기 트랜잭션트랜잭션mode가 "readwrite"인 것입니다.

2.7.1. 트랜잭션 생명주기

트랜잭션에는 상태가 있으며, 다음 중 하나입니다:

active

트랜잭션이 처음 생성될 때, 그리고 트랜잭션과 연관된 요청에서 이벤트가 디스패치되는 동안 이 상태가 됩니다.

이 상태일 때는 트랜잭션에 대해 새로운 요청을 할 수 있습니다.

inactive

트랜잭션이 생성된 후 제어가 이벤트 루프로 돌아오거나, 이벤트가 디스패치되지 않을 때 이 상태가 됩니다.

이 상태일 때는 트랜잭션에 대해 요청을 할 수 없습니다.

committing

트랜잭션과 연관된 모든 요청이 완료되면, 트랜잭션은 커밋을 시도하면서 이 상태가 됩니다.

이 상태일 때는 트랜잭션에 대해 요청을 할 수 없습니다.

finished

트랜잭션이 커밋되거나 중단(abort)된 후 이 상태가 됩니다.

이 상태일 때는 트랜잭션에 대해 요청을 할 수 없습니다.

트랜잭션은 단기간만 유지되는 것이 권장됩니다. 이는 아래의 자동 커밋 기능에 의해 장려됩니다.

참고: 작성자는 트랜잭션을 live 상태로 오래 유지시킬 수도 있습니다. 그러나 이런 사용 패턴은 사용자 경험 저하를 유발할 수 있으므로 권장되지 않습니다.

트랜잭션생명주기는 다음과 같습니다:

  1. 트랜잭션은 생성될 때 scopemode를 가집니다. 생성 시 stateactive입니다.

  2. 구현체가 트랜잭션의 scopemode의 제약을 아래 트랜잭션 스케줄링에 따라 만족시킬 수 있을 때, 데이터베이스 작업을 큐에 추가해서 트랜잭션을 비동기로 시작해야 합니다.

    트랜잭션이 시작되면, 구현체는 트랜잭션에 대해 요청된 요청을 실행할 수 있습니다. 요청은 트랜잭션에 대해 요청된 순서대로 실행되어야 하며, 결과 역시 해당 트랜잭션에 대해 요청된 순서대로 반환되어야 합니다. 서로 다른 트랜잭션의 요청 결과 반환 순서는 보장되지 않습니다.

    참고: 트랜잭션의 mode는 서로 다른 트랜잭션의 요청이 어떤 순서로 실행되더라도 데이터베이스에 저장되는 결과 데이터에 영향을 주지 않도록 보장합니다.

  3. 트랜잭션과 연관된 각 요청처리되면, success 또는 error event가 발생합니다. 이벤트가 디스패치되는 동안 트랜잭션의 stateactive가 되어 추가 요청을 트랜잭션에 할 수 있습니다. 이벤트 디스패치가 끝나면 state는 다시 inactive가 됩니다.

  4. 트랜잭션은 중단(abort)될 수 있으며, finished 상태가 되기 전까지 언제든 중단될 수 있습니다. 이는 트랜잭션이 active가 아니거나 아직 시작되지 않은 경우에도 가능합니다.

    abort() 를 명시적으로 호출하면 중단(abort)이 시작됩니다. 스크립트에서 처리되지 않은 요청이 실패한 경우에도 중단이 시작됩니다.

    트랜잭션이 중단되면, 구현체는 해당 트랜잭션 동안 데이터베이스에 이루어진 모든 변경사항을 롤백(undo)해야 합니다. 이는 오브젝트 스토어의 내용 변경뿐 아니라 오브젝트 스토어인덱스의 추가/삭제도 포함됩니다.

  5. 구현체는 트랜잭션이 inactive이고, 트랜잭션에 대해 요청된 모든 요청이 완료되고 결과가 처리되었으며, 새로운 요청이 추가되지 않았고 트랜잭션이 중단되지 않았을 때 커밋을 시도해야 합니다.

    commit() 를 명시적으로 호출하면 스크립트에서 요청 결과를 기다리지 않고 커밋을 시작합니다.

    커밋할 때 트랜잭션의 statecommitting이 됩니다. 구현체는 트랜잭션에 대해 요청된 변경사항을 데이터베이스에 원자적으로 기록해야 하며, 즉 모든 변경사항을 기록하거나, 오류(예: 디스크 기록 오류)가 발생하면 아무 변경도 기록하지 않아야 하며, 트랜잭션 중단 절차를 따라야 합니다.

  6. 트랜잭션이 커밋되거나 중단되면, statefinished가 됩니다.

구현체는 트랜잭션이 active일 때 언제든 요청추가할 수 있도록 해야 합니다. 트랜잭션이 아직 시작되지 않은 경우에도 마찬가지입니다. 트랜잭션이 시작되기 전에는 요청을 실행하지 않아야 하지만, 요청과 그 순서는 반드시 기록해 두어야 합니다.

트랜잭션live 상태로, 생성된 순간부터 statefinished가 될 때까지입니다.

Indexed Database 트랜잭션 정리를 하려면 다음 절차를 실행합니다. 트랜잭션이 정리되었으면 true를, 그렇지 않으면 false를 반환합니다.

  1. 현행 이벤트 루프cleanup event loop가 일치하는 트랜잭션이 하나도 없으면 false를 반환합니다.

  2. 현행 이벤트 루프cleanup event loop가 일치하는 각 트랜잭션 transaction에 대해:

    1. transactionstateinactive로 설정합니다.

    2. transactioncleanup event loop를 지웁니다.

  3. true를 반환합니다.

참고: 이 단계는 [HTML]에서 호출됩니다. 이는 스크립트에서 transaction() 을 호출하여 생성한 트랜잭션을, 스크립트 호출 작업이 완료되면 비활성화하도록 보장합니다. 각 트랜잭션마다 최대 한 번만 실행됩니다.

IDBTransaction에서 complete 타입 이벤트는 트랜잭션이 성공적으로 커밋된 경우 발생합니다.

IDBTransaction에서 abort 타입 이벤트는 트랜잭션중단된 경우 발생합니다.

2.7.2. 트랜잭션 스케줄링

다음 제약들은 트랜잭션이 언제 시작될 수 있는지를 정의합니다:

구현체는 추가적인 제약을 둘 수 있습니다. 예를 들어, 구현체는 시작되는 scope가 겹치지 않는 읽기/쓰기 트랜잭션을 병렬로 실행할 필요는 없으며, 동시에 시작되는 트랜잭션의 수를 제한할 수도 있습니다.

참고: 위 제약들은 다음을 의미합니다:

2.7.3. 업그레이드 트랜잭션

업그레이드 트랜잭션트랜잭션mode 가 "versionchange"인 것입니다.

업그레이드 트랜잭션connection을 통해 데이터베이스를 열 때, 지정된 version이 현재 version보다 클 경우 데이터베이스 업그레이드 단계에서 자동으로 생성됩니다. 이 트랜잭션upgradeneeded 이벤트 핸들러 내에서 활성화됩니다.

참고: 업그레이드 트랜잭션데이터베이스에서 오브젝트 스토어인덱스의 생성, 이름 변경, 삭제를 가능하게 합니다.

업그레이드 트랜잭션은 독점적입니다. 데이터베이스 연결 열기 단계는 업그레이드 트랜잭션live 상태일 때 데이터베이스에 하나의 connection만 열려 있도록 보장합니다. upgradeneeded 이벤트는 발생하지 않으며, 업그레이드 트랜잭션도 시작되지 않습니다. 다른 connection이 모두 닫힐 때까지 대기합니다. 이는 이전 모든 트랜잭션이 완료되는 것을 보장합니다.

업그레이드 트랜잭션live인 동안 동일한 데이터베이스에 추가 connection을 열려는 시도는 지연되며, 동일한 connection에서 transaction() 을 호출해 추가 트랜잭션을 시작하려고 하면 예외가 발생합니다. 이는 다른 트랜잭션이 동시에 live 상태가 되지 않도록 하고, 업그레이드 트랜잭션live인 동안 동일한 데이터베이스에 새로운 트랜잭션이 큐잉되지 않도록 보장합니다.

또한 업그레이드 트랜잭션이 완료되면 데이터베이스오브젝트 스토어인덱스 집합은 이후 모든 connection트랜잭션의 생명주기 동안 일정하게 유지됩니다.

2.8. 요청

데이터베이스에서 모든 비동기 작업은 요청을 통해 수행됩니다. 각 요청은 하나의 작업을 나타냅니다.

요청에는 processed 플래그가 있으며, 초기값은 false입니다. 이 플래그는 요청에 연관된 작업이 실행되면 true로 설정됩니다.

요청processed 상태란, processed 플래그가 true일 때를 의미합니다.

요청에는 done 플래그가 있으며, 초기값은 false입니다. 이 플래그는 요청에 연관된 작업의 결과가 사용 가능할 때 true로 설정됩니다.

요청에는 source 오브젝트가 있습니다.

요청에는 resulterror가 있으며, done 플래그가 true가 되기 전까지는 접근할 수 없습니다.

요청에는 transaction이 있으며, 초기값은 null입니다. 요청이 트랜잭션에 추가될 때 설정됩니다. 트랜잭션에 대해 요청을 비동기적으로 실행 단계에서 설정됩니다.

요청이 만들어지면, 새로운 요청이 반환되며 done 플래그는 false입니다. 요청이 성공적으로 완료되면 done 플래그가 true가 되고, result가 해당 요청의 결과로 설정됩니다. 그리고 success 타입 이벤트가 요청에 발생합니다.

작업 중 오류가 발생하면 요청의 done 플래그가 true가 되고, error가 오류로 설정되며, error 타입 이벤트가 요청에 발생합니다.

요청get the parent 알고리즘은 요청의 transaction을 반환합니다.

참고: 요청은 일반적으로 재사용되지 않지만, 예외가 있습니다. 커서를 반복(iterate)할 때, 반복의 성공은 커서를 열 때 사용한 동일한 요청 오브젝트로 보고됩니다. 그리고 업그레이드 트랜잭션이 필요한 경우, 같은 open requestupgradeneeded 이벤트와 최종 open 작업 결과 모두에 사용됩니다. 어떤 경우에는 요청의 done 플래그가 false로 설정된 뒤 다시 true가 되며, result가 변경되거나 error가 설정될 수 있습니다.

2.8.1. Open 요청

open request요청 중, connection을 열거나 데이터베이스를 삭제할 때 사용하는 특수 타입입니다. successerror 이벤트 외에도, blockedupgradeneeded 이벤트가 open request에 발생하여 진행 상황을 알릴 수 있습니다.

sourceopen request일 때는 항상 null입니다.

transactionopen request일 때는 upgradeneeded 이벤트가 발생하지 않는 한 null입니다.

open requestget the parent 알고리즘은 null을 반환합니다.

2.8.2. 연결 큐

Open requestconnection queue에서 처리됩니다. 이 큐에는 해당 open request와 연관된 storage keyname이 모두 포함됩니다. 큐에 추가된 connection queue의 요청들은 순서대로 처리되며, 각 요청은 완료되어야 다음 요청을 처리할 수 있습니다. open request는 다른 connection에 의해 블록될 수 있으며, 해당 connection이 닫힘 상태가 되어야 요청이 완료되어 이후 요청이 처리될 수 있습니다.

참고: connection queue현행 표준의 task queue가 아니며, 요청들은 특정 브라우징 컨텍스트와 상관없이 처리됩니다. 완료된 open request에 이벤트 전달은 여전히 task queue 와 해당 요청이 만들어진 컨텍스트의 이벤트 루프를 통해 진행됩니다.

2.9. 키 범위

레코드는 오브젝트 스토어인덱스에서 또는 키 범위를 이용하여 조회할 수 있습니다. 키 범위는 키로 사용되는 데이터 타입에 대한 연속된 구간입니다.

키 범위에는 연관된 하한(null 또는 )이 있습니다.

키 범위에는 연관된 상한(null 또는 )이 있습니다.

키 범위에는 연관된 하한 개방 플래그가 있습니다. 별도 명시가 없는 한 false입니다.

키 범위에는 연관된 상한 개방 플래그가 있습니다. 별도 명시가 없는 한 false입니다.

키 범위하한상한과 동일할 수도 있습니다. 키 범위하한상한보다 클 수는 없습니다.

키 범위특정 키만 포함한다면, 하한상한이 모두 key와 같습니다.

key키 범위에 포함되어 있다고 하려면 range에 대해 다음 두 조건을 모두 만족해야 합니다:

참고:

무한 키 범위키 범위에서 하한상한이 모두 null인 경우입니다. 모든 무한 키 범위 내에 포함됩니다.

값을 키 범위로 변환하려면 value와 (선택적) null disallowed flag를 받아 다음 절차를 실행합니다:

  1. value키 범위면, value를 반환한다.

  2. value가 undefined나 null이면, null disallowed flag가 true면 "DataError" DOMExceptionthrow하고, 아니면 무한 키 범위를 반환한다.

  3. key값을 키로 변환 단계와 value로 얻는다. 예외 발생 시 재throw한다.

  4. key가 "invalid value" 또는 "invalid type"이면 "DataError" DOMExceptionthrow한다.

  5. key만 포함하는 키 범위생성하여 반환한다.

잠재적으로 유효한 키 범위는 ECMAScript 값 중 키 범위로 변환될 수 있는 타입을 가진 값입니다. 해당 값이 실제로 키 범위로 변환될 때 예외가 발생하는지 여부는 중요하지 않습니다.

참고: 예를 들어, detached BufferSource잠재적으로 유효한 키 범위이지만 값을 키 범위로 변환에 사용되면 예외가 발생합니다.

ECMAScript value잠재적으로 유효한 키 범위인지 판단하려면 다음 절차를 실행합니다:

  1. value키 범위라면 true를 반환한다.

  2. key값을 키로 변환 단계와 value로 얻는다.

  3. key가 "invalid type"이면 false를 반환한다.

  4. 그 외에는 true를 반환한다.

참고: getAll()getAllKeys() 메서드는 첫 번째 인자 처리에 잠재적으로 유효한 키 범위인지 판단 단계를 사용합니다. 인자가 잠재적으로 유효한 키 범위라면 getAll()getAllKeys() 는 해당 인자로 값을 키 범위로 변환을 실행합니다. 그렇지 않으면 IDBGetAllOptions 를 첫 인자로 사용합니다.

getAll()getAllKeys()Date, Array, ArrayBuffer 첫 인자가 값을 키로 변환 단계에서 "invalid value"를 반환하면 예외를 발생시킵니다. 예를 들어, NaN Date 인자로 getAll() 을 실행하면, 기본값의 IDBGetAllOptions 딕셔너리를 사용하는 대신 예외가 발생합니다.

2.10. 커서

커서인덱스 또는 오브젝트 스토어의 레코드 범위를 특정 방향으로 순차적으로 탐색하는 데 사용됩니다.

커서source handle을 가지며, 이는 커서를 연 인덱스 핸들 또는 오브젝트 스토어 핸들입니다.

커서트랜잭션을 가지며, 이는 커서의 source handle에서 가져온 트랜잭션입니다.

커서레코드 범위를 가지며, 이는 인덱스 또는 오브젝트 스토어 중 하나입니다.

커서source를 가지며, 이는 커서의 source handle에서 가져온 인덱스 또는 오브젝트 스토어입니다. 커서의 source는 커서가 탐색하는 레코드가 어떤 인덱스 또는 오브젝트 스토어와 연관되는지 나타냅니다. 만약 커서의 source handle인덱스 핸들이면, 커서의 source그 인덱스 핸들이 연관된 인덱스입니다. 그렇지 않으면, 커서의 source오브젝트 스토어 핸들이 연관된 오브젝트 스토어입니다.

커서direction을 가지며, 이는 커서가 반복(iterate)될 때 레코드의 키를 단조 증가/감소 순서로 이동할지, 인덱스를 순회할 때 중복 값을 건너뛸지 결정합니다. 커서의 방향은 초기 위치가 source의 시작 또는 끝이 될지 또한 결정합니다. 커서의 direction은 다음 중 하나입니다:

"next"

이 방향은 커서를 source의 시작 위치에서 열게 합니다. 반복 시 커서는 중복을 포함한 모든 레코드를 키의 단조 증가 순서로 반환해야 합니다.

"nextunique"

이 방향은 커서를 source의 시작 위치에서 열게 합니다. 반복 시 커서는 동일한 키를 가진 레코드는 반환하지 않고, 그 외의 모든 레코드를 키의 단조 증가 순서로 반환합니다. 중복 값이 있는 모든 키에 대해 첫 번째 레코드만 반환됩니다. source오브젝트 스토어이거나 인덱스unique 플래그가 true일 경우, 이 방향은 "next"와 정확히 동일하게 동작합니다.

"prev"

이 방향은 커서를 source의 끝 위치에서 열게 합니다. 반복 시 커서는 중복을 포함한 모든 레코드를 키의 단조 감소 순서로 반환해야 합니다.

"prevunique"

이 방향은 커서를 source의 끝 위치에서 열게 합니다. 반복 시 커서는 동일한 키를 가진 레코드는 반환하지 않고, 그 외의 모든 레코드를 키의 단조 감소 순서로 반환합니다. 중복 값이 있는 모든 키에 대해 첫 번째 레코드만 반환됩니다. source오브젝트 스토어이거나 인덱스unique 플래그가 true일 경우, 이 방향은 "prev"와 정확히 동일하게 동작합니다.

커서는 범위 내에서 position을 가집니다. 커서가 탐색하는 레코드 목록이 커서가 범위를 모두 탐색하기 전에 변경될 수 있습니다. 이를 처리하기 위해 커서는 position을 인덱스가 아닌, 직전에 반환된 레코드의 로 유지합니다. 앞으로 탐색하는 커서는 다음 레코드 탐색 시 직전 반환된 키보다 키를 가진 레코드 중 가장 작은 것을 반환합니다. 뒤로 탐색하는 커서는 그 반대로, 직전 반환된 키보다 작은 키 중 가장 큰 레코드를 반환합니다.

인덱스를 탐색하는 커서는 더 복잡합니다. 동일한 키를 가진 여러 레코드가 있을 수 있으므로 으로도 정렬됩니다. 인덱스 탐색 시 커서object store position도 가지며, 이는 인덱스에서 직전에 찾은 레코드을 나타냅니다. positionobject store position 모두 다음 적합한 레코드를 찾을 때 사용됩니다.

커서keyvalue를 가지며, 이는 마지막으로 탐색한 레코드을 나타냅니다.

커서got value flag를 가지며, 이 플래그가 false일 때 커서는 다음 값을 로딩 중이거나 범위의 끝에 도달한 상태입니다. true일 때는 커서가 현재 값을 보유하고 다음 값 탐색 준비가 된 상태임을 나타냅니다.

커서의 source오브젝트 스토어라면, 커서의 effective object store는 그 오브젝트 스토어이고, effective key는 커서의 position입니다. 커서의 source인덱스라면, effective object store는 그 인덱스가 참조하는 오브젝트 스토어이고, effective key는 커서의 object store position입니다.

커서request도 가지며, 이는 커서를 열 때 사용한 요청입니다.

커서key only flag도 가지며, 커서의 value가 API를 통해 노출되는지 여부를 나타냅니다.

2.11. 키 생성기

오브젝트 스토어를 생성할 때 키 생성기를 사용하도록 지정할 수 있습니다. 키 생성기는 오브젝트 스토어에 레코드가 삽입될 때 별도로 지정하지 않은 경우 키를 생성하는 데 사용됩니다.

키 생성기에는 현재 숫자가 있습니다. 현재 숫자는 항상 253 (9007199254740992) + 1 이하의 양의 정수입니다. 키 생성기현재 숫자의 초기값은 1이며, 연관된 오브젝트 스토어가 생성될 때 설정됩니다. 현재 숫자는 키가 생성될 때마다 증가하며, 명시적으로 키를 지정하면 특정 값으로 갱신될 수 있습니다.

참고: 키 생성기를 사용하는 각 오브젝트 스토어는 별도의 생성기를 가집니다. 즉, 하나의 오브젝트 스토어와 상호작용해도 다른 오브젝트 스토어의 키 생성기는 영향을 받지 않습니다.

키 생성기의 현재 숫자를 수정하는 것은 데이터베이스 작업의 일부로 간주됩니다. 즉, 작업이 실패하여 롤백되면 현재 숫자도 작업 시작 전의 값으로 되돌아갑니다. 이는 키 생성기를 사용할 때 현재 숫자가 1 증가하는 경우와, 레코드를 명시적으로 키 값과 함께 저장하는 경우 모두 적용됩니다.

마찬가지로, 트랜잭션이 중단(abort)되는 경우, 해당 트랜잭션의 scope 내 모든 오브젝트 스토어의 키 생성기 현재 숫자도 트랜잭션 시작 전 값으로 되돌아갑니다.

키 생성기의 현재 숫자는 데이터베이스 작업이 롤백되는 경우를 제외하고는 절대 감소하지 않습니다. 레코드를 오브젝트 스토어에서 삭제해도 오브젝트 스토어의 키 생성기는 영향을 받지 않습니다. clear() 메서드 등으로 모든 레코드를 삭제해도 오브젝트 스토어의 키 생성기 현재 숫자는 영향을 받지 않습니다.

레코드를 저장할 때 를 명시하지 않으면, 키가 생성됩니다.

오브젝트 스토어 store에서 키 생성하려면 다음 절차를 실행합니다:

  1. generatorstore키 생성기로 한다.

  2. keygenerator현재 숫자로 한다.

  3. key가 253 (9007199254740992)보다 크면 실패를 반환한다.

  4. generator현재 숫자를 1 증가시킨다.

  5. key를 반환한다.

레코드를 저장할 때 를 명시하면, 연관된 키 생성기가 갱신될 수 있습니다.

오브젝트 스토어 storekey키 생성기 갱신 가능성을 판단하려면 다음 절차를 실행합니다:

  1. keytypenumber가 아니면 중단한다.

  2. valuekeyvalue로 한다.

  3. valuevalue와 253 (9007199254740992) 중 더 작은 값으로 한다.

  4. valuevalue 이하의 가장 큰 정수로 한다.

  5. generatorstore키 생성기로 한다.

  6. valuegenerator현재 숫자보다 크거나 같으면, generator현재 숫자value + 1로 한다.

참고: 인라인 키를 사용하는 오브젝트 스토어는 저장 값에서 오브젝트 스토어의 key path로 지정된 속성을 설정하고, 아웃 오브젝트 키를 사용하는 오브젝트 스토어는 저장 레코드에 키 인자를 전달하여 키를 지정할 수 있습니다.

명시적으로 지정된 typenumber인 키만 키 생성기의 현재 숫자에 영향을 미칩니다. typedate, array(내부 키에 관계없이), binary, string(숫자로 해석 가능해도)인 키는 키 생성기의 현재 숫자에 영향을 주지 않습니다. typenumber이지만 value가 1보다 작은 키도 현재 숫자에 영향을 주지 않습니다(항상 더 작기 때문).

키 생성기의 현재 숫자가 253 (9007199254740992) 이상이 되면 이후 키 생성기를 사용해 를 생성하려고 시도하면 "ConstraintError" DOMException이 발생합니다. 명시적으로 키를 지정해서 오브젝트 스토어에 레코드를 삽입하는 것은 가능하지만, 이 경우 키 생성기를 다시 사용하려면 오브젝트 스토어를 삭제하고 새로 만들어야 합니다.

참고: 이 한계는 9007199254740992보다 큰 정수는 ECMAScript Number로 고유하게 표현할 수 없기 때문입니다. 예를 들어, ECMAScript에서는 9007199254740992 + 1 === 9007199254740992입니다.

키 생성기를 정상적으로 사용한다면 이 한계에 도달하는 일은 없습니다. 예를 들어 매초 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번 키

다음 예시는 인라인 키 생성기로 오브젝트를 오브젝트 스토어에 저장할 때 동작 차이를 보여줍니다.

다음 조건이 모두 참이라면:

그러면 키 생성기가 제공하는 값이 키 값으로 사용됩니다. 아래 예에서 오브젝트 스토어의 key path는 "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);
};

다음 조건이 모두 참이라면:

그러면 key path 속성에 있는 값이 사용됩니다. 자동 생성 는 사용되지 않습니다. 아래 예에서 key path는 "foo.bar"이고, 실제 객체에 bar 속성 값이 10({ 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);
};

다음 예시는 명시된 인라인 key path에 의해 정의되지만 실제로 일치하는 속성이 없을 때 동작을 보여줍니다. 키 생성기가 제공하는 값이 키 값으로 사용되며, 시스템은 계층 구조에서 필요한 만큼의 속성을 생성합니다. 아래 예에서 key path는 "foo.bar.baz"이고, 실제 객체에는 foo 속성이 없으며 { zip: {} }입니다. 오브젝트가 오브젝트 스토어에 저장될 때 foo, bar, baz 속성이 각각 자식으로 생성되어 foo.bar.baz에 값을 할당할 수 있게 됩니다. 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 will be: { zip: {}, foo: { bar: { baz: 1 } } }
    console.assert(value.foo.bar.baz === 1);
  };
};

원시값에 속성을 저장하려 하면 오류가 발생합니다. 아래 첫 번째 예에서 오브젝트 스토어의 key path는 "foo"이고, 실제 객체는 값 4인 원시값입니다. 해당 원시값에 속성을 정의하려 하면 실패합니다.

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

// 키 생성은 이 원시값에 key path 속성을 만들고 저장하려 시도합니다.
store.put(4); // DataError 발생

2.12. 레코드 스냅샷

레코드 스냅샷오브젝트 스토어 레코드 또는 인덱스 레코드에서 복사된 키와 값을 포함합니다.

레코드 스냅샷에는 key가 있으며, 이는 입니다.

레코드 스냅샷에는 value가 있으며, 이는 입니다.

참고: 인덱스 레코드의 경우, 스냅샷의 value는 해당 레코드의 참조 값 복사본입니다. 오브젝트 스토어 레코드의 경우, 스냅샷의 value레코드 값입니다.

레코드 스냅샷에는 primary key도 있으며, 이는 입니다.

참고: 인덱스 레코드의 경우, 스냅샷의 primary key는 레코드의 이며, 이는 인덱스의 참조 오브젝트 스토어 내 해당 레코드의 키입니다. 오브젝트 스토어 레코드의 경우, 스냅샷의 primary keykey는 동일한 이며, 이는 레코드의 키입니다.

3. 예외

이 문서에서 사용되는 모든 예외는 DOMException 또는 DOMException 파생 인터페이스이며, [WEBIDL]에 정의되어 있습니다.

아래 표는 이 문서에서 사용되는 DOMException 이름들과 각 예외의 사용 설명을 나열합니다.

타입 설명
AbortError 요청이 중단(abort)되었습니다.
ConstraintError 트랜잭션 내 변이(mutation) 작업이 제약 조건을 만족하지 않아 실패했습니다.
DataCloneError 저장되는 데이터가 내부 구조화 복제 알고리즘에 의해 복제(clone)될 수 없습니다.
DataError 작업에 제공된 데이터가 요구 조건을 충족하지 않습니다.
InvalidAccessError 오브젝트에 대해 잘못된 작업이 수행되었습니다.
InvalidStateError 오브젝트에서 허용되지 않은 작업이 호출되었거나, 허용되지 않은 시점에 호출되었거나, 이미 삭제되거나 제거된 소스 오브젝트에 대해 요청이 이루어진 경우입니다.
NotFoundError 요청된 데이터베이스 오브젝트를 찾을 수 없어서 작업이 실패했습니다.
NotReadableError 요청된 데이터를 포함하는 하부 저장소를 읽을 수 없어 작업이 실패했습니다.
SyntaxError keyPath 인자가 잘못된 키 경로를 포함합니다.
ReadOnlyError 변이 작업이 읽기 전용 트랜잭션에서 시도되었습니다.
TransactionInactiveError 현재 활성(active) 상태가 아니거나 이미 완료된 트랜잭션에 대해 요청이 이루어진 경우입니다.
UnknownError 작업이 데이터베이스 자체와 관련이 없거나 다른 오류로 인해 일시적으로 실패했습니다.
VersionError 기존 버전보다 낮은 버전으로 데이터베이스를 열려고 시도한 경우입니다.

DOMException 이름 외에도, QuotaExceededError 예외 타입은 작업이 남은 저장 공간이 부족하거나 저장소 할당량(quota)을 초과해 사용자가 더 많은 공간을 허락하지 않은 경우에 사용됩니다.

참고: 여러 Indexed DB 작업이 동일한 유형의 오류를 발생시킬 수 있고, 하나의 작업에서도 여러 이유로 동일한 오류가 발생할 수 있으므로, 구현에서는 개발자가 오류 원인을 식별할 수 있도록 더 구체적인 메시지를 제공하는 것이 권장됩니다.

4. API

API 메서드는 호출 스레드를 차단하지 않고 반환됩니다. 모든 비동기 작업은 즉시 IDBRequest 인스턴스를 반환합니다. 이 객체는 처음에는 작업 결과에 대한 정보를 포함하지 않습니다. 정보가 사용 가능해지면, 요청(request)에서 이벤트가 발생하고 해당 정보를 IDBRequest 인스턴스의 속성으로 접근할 수 있습니다.

이러한 작업의 task sourcedatabase access task source입니다.

데이터베이스 작업을 큐에 추가하려면 queue a taskdatabase access task source에 대해 수행합니다.

4.1. IDBRequest 인터페이스

IDBRequest 인터페이스는 데이터베이스데이터베이스 오브젝트에 대한 비동기 요청의 결과를 event handler IDL attribute를 통해 접근할 수 있게 해줍니다 [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

요청이 완료되면 result를 반환하며, 요청이 실패하면 undefined를 반환합니다. 요청이 아직 완료되지 않았다면 "InvalidStateError" DOMException이 발생합니다.

request . error

요청이 완료되면 error(DOMException)을 반환하며, 요청이 성공했다면 null을 반환합니다. 요청이 아직 완료되지 않았다면 "InvalidStateError" DOMException이 발생합니다.

request . source

요청이 만들어진 IDBObjectStore, IDBIndex, IDBCursor를 반환하며, open request라면 null을 반환합니다.

request . transaction

요청이 만들어진 IDBTransaction을 반환합니다. open request라면, upgrade transactionlive인 동안에는 upgrade transaction을, 그렇지 않으면 null을 반환합니다.

request . readyState

요청이 완료될 때까지 "pending"을 반환하며, 완료되면 "done"을 반환합니다.

result getter 단계:
  1. thisdone flag가 false이면, "InvalidStateError" DOMException을 throw한다.

  2. thisresult를 반환하며, 요청이 오류로 끝났다면 undefined를 반환한다.

error getter 단계:
  1. thisdone flag가 false이면, "InvalidStateError" DOMException을 throw한다.

  2. thiserror를 반환하며, 오류가 없으면 null을 반환한다.

source getter 단계는 thissource를 반환하며, source가 설정되지 않았다면 null을 반환합니다.

transaction getter 단계는 thistransaction을 반환합니다.

참고: transaction getter는 open() 등 특정 요청에 대해 null을 반환할 수 있습니다.

readyState getter 단계는 thisdone flag가 false이면 "pending"을 반환하고, 그렇지 않으면 "done"을 반환합니다.

onsuccess 속성은 event handler IDL attribute이며, event handler event typesuccess입니다.

onerror 속성은 event handler IDL attribute이며, event handler event typeerror 입니다.

IDBDatabase 메서드가 open request를 반환할 때, blockedupgradeneeded 이벤트를 수신할 수 있도록 확장된 인터페이스를 사용합니다.

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

onblocked 속성은 event handler IDL attribute이며, event handler event typeblocked입니다.

onupgradeneeded 속성은 event handler IDL attribute이며, event handler event typeupgradeneeded입니다.

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 getter 단계는 초기화될 때의 값을 반환합니다. 이는 데이터베이스의 이전 버전을 나타냅니다.

newVersion getter 단계는 초기화될 때의 값을 반환합니다. 이는 데이터베이스의 새로운 버전을 나타내며, 데이터베이스가 삭제되는 경우 null입니다. 데이터베이스 업그레이드 단계를 참고하세요.

이벤트는 DOM § 2.5 이벤트 생성에 정의된 대로 생성됩니다.

버전 변경 이벤트 발생e라는 이름으로 targetoldVersionnewVersion을 제공하여 수행하려면 다음 절차를 실행합니다:

  1. eventIDBVersionChangeEvent를 사용하여 이벤트 생성 결과로 한다.

  2. eventtype 속성을 e로 설정한다.

  3. eventbubblescancelable 속성을 false로 설정한다.

  4. eventoldVersion 속성을 oldVersion으로 설정한다.

  5. eventnewVersion 속성을 newVersion으로 설정한다.

  6. legacyOutputDidListenersThrowFlag를 false로 한다.

  7. event dispatchlegacyOutputDidListenersThrowFlag와 함께 target에 대해 event로 실행한다.

  8. legacyOutputDidListenersThrowFlag를 반환한다.

    참고: 이 알고리즘의 반환값이 항상 사용되는 것은 아닙니다.

4.3. IDBFactory 인터페이스

데이터베이스 오브젝트는 IDBFactory 인터페이스의 메서드를 통해 접근할 수 있습니다. 이 인터페이스를 구현하는 단일 오브젝트가 Indexed DB 작업을 지원하는 환경의 전역 스코프에 존재합니다.

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)

지정한 데이터베이스에 현재 버전(존재하지 않으면 1)으로 connection을 열려고 시도합니다. 요청이 성공하면 requestresult 값이 connection이 됩니다.

request = indexedDB . open(name, version)

지정한 데이터베이스version으로 connection을 열려고 시도합니다. 데이터베이스가 더 낮은 버전으로 이미 존재하고, versionchange 이벤트에 반응하여 닫히지 않는 connection이 열려 있으면 요청이 모두 닫힐 때까지 블록되고, 이후 업그레이드가 발생합니다. 데이터베이스가 이미 더 높은 버전으로 존재하면 요청이 실패합니다. 요청이 성공하면 requestresult 값이 connection이 됩니다.

request = indexedDB . deleteDatabase(name)

지정한 데이터베이스를 삭제하려고 시도합니다. 이미 데이터베이스가 존재하고, versionchange 이벤트에 반응하여 닫히지 않는 connection이 열려 있으면 요청이 모두 닫힐 때까지 블록됩니다. 요청이 성공하면 requestresult 값은 null이 됩니다.

result = await indexedDB . databases()

현재 storage key 내 데이터베이스 이름과 버전의 스냅샷을 객체 리스트로 반환하는 promise를 반환합니다.

이 API는 웹 애플리케이션이 이전 버전 사이트의 데이터베이스를 정리하는 등 introspect 용도로 사용할 수 있도록 설계되었습니다. 반환 결과는 스냅샷이므로, 데이터 수집 또는 응답 전달이 이 컨텍스트나 다른 컨텍스트에서 데이터베이스 생성, 업그레이드, 삭제 요청과 어떤 순서로 처리되는지에 대해 보장하지 않습니다.

open(name, version) 메서드 단계는 다음과 같습니다:

  1. version이 0이면, throw TypeError.

  2. environmentthisrelevant settings object로 한다.

  3. storageKeyobtain a storage keyenvironment로 실행한 결과로 한다. 실패가 반환되면 throw "SecurityError" DOMException 하고, 이 단계를 중단한다.

  4. request를 새 open request로 한다.

  5. 다음 단계를 병렬로 실행한다:

    1. result데이터베이스 연결 열기 결과로 한다. 인자로는 storageKey, name, version(있으면) 또는 없으면 undefined, request를 사용한다.

      version이 주어지지 않으면? version이 없고 해당 이름의 데이터베이스가 이미 존재하면, 버전을 변경하지 않고 커넥션을 연다. 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 이벤트 발생 단계를 사용하지 않는 이유는? 이 시점에서 요청에 연관된 트랜잭션이 없으므로, 해당 단계들(이벤트 디스패치 전후에 트랜잭션 활성/비활성화)은 적용되지 않습니다.
  6. request에 대해 새 IDBOpenDBRequest 객체를 반환한다.

deleteDatabase(name) 메서드 단계는 다음과 같습니다:

  1. environmentthisrelevant settings object로 한다.

  2. storageKeyobtain a storage keyenvironment로 실행한 결과로 한다. 실패가 반환되면 throw "SecurityError" DOMException 하고, 이 단계를 중단한다.

  3. request를 새 open request로 한다.

  4. 다음 단계를 병렬로 실행한다:

    1. result데이터베이스 삭제 결과로 한다. 인자로는 storageKey, name, request를 사용한다.

    2. requestprocessed flag를 true로 한다.

    3. 데이터베이스 작업을 큐에 추가하여 다음 단계를 실행한다:

      1. result가 에러이면, requesterrorresult로 하고, requestdone flag를 true로 하고, 이벤트 발생error 이름으로 request에 대해 실행하며, bubblescancelable 속성은 true로 초기화한다.

      2. 그렇지 않으면, requestresult를 undefined로 하고, requestdone flag를 true로 하고, 버전 변경 이벤트 발생success 이름으로 request에 대해 result와 null로 실행한다.

        success 이벤트 발생이나 error 이벤트 발생 단계를 사용하지 않는 이유는? 이 요청에 연관된 트랜잭션이 없으므로, 해당 단계들(이벤트 디스패치 전후에 트랜잭션 활성/비활성화)은 적용되지 않습니다.

        또한, 여기서 success 이벤트는 IDBVersionChangeEvent 이며, oldVersionnewVersion 정보가 포함됩니다.

  5. request에 대해 새 IDBOpenDBRequest 객체를 반환한다.

databases() 메서드 단계는 다음과 같습니다:

  1. environmentthisrelevant settings object로 한다.

  2. storageKeyobtain a storage keyenvironment로 실행한 결과로 한다. 실패가 반환되면 a promise rejected with "SecurityError" DOMException을 반환한다.

  3. p새 promise로 한다.

  4. 다음 단계를 병렬로 실행한다:

    1. databasesset of 데이터베이스 in storageKey로 한다. 어떤 이유로든 이를 결정할 수 없다면, 데이터베이스 작업을 큐에 추가하여 p를 적절한 에러로 reject(예: "UnknownError" DOMException)하고, 이 단계를 종료한다.

    2. result를 새 list로 한다.

    3. db in databases에 대해:

      1. dbversion이 0이면, continue한다.

      2. info를 새 IDBDatabaseInfo 딕셔너리로 한다.

      3. infoname 속성을 dbname으로 설정한다.

      4. infoversion 속성을 dbversion으로 설정한다.

      5. info를 result에 추가한다.

    4. 데이터베이스 작업을 큐에 추가하여 p를 result로 resolve한다.

  5. p를 반환한다.

🚧 databases() 메서드는 이번 판에서 새로 추가되었습니다. Chrome 71, Edge 79, Firefox 126, Safari 14에서 지원됩니다. 🚧
result = indexedDB . cmp(key1, key2)

두 값을 로 비교합니다. 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. 두 키 비교ab로 실행한 결과를 반환한다.

4.4. IDBDatabase 인터페이스

IDBDatabase 인터페이스는 커넥션데이터베이스와 연결된 객체를 나타냅니다.

IDBDatabase 객체는 연관된 커넥션close pending flag가 false이고, 다음 타입 중 하나의 이벤트 리스너가 등록되어 있으면 가비지 컬렉션되어서는 안 됩니다: abort, error, versionchange. 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

데이터베이스의 이름을 반환합니다.

connection . version

데이터베이스의 버전을 반환합니다.

name getter 단계는 this의 연관된 데이터베이스이름을 반환합니다.

참고: name 속성은 thisclose pending flag가 true여도 이 이름을 반환합니다. 즉, 이 속성 값은 IDBDatabase 인스턴스의 생명주기 동안 항상 일정하게 유지됩니다.

version getter 단계는 this버전을 반환합니다.

이 값은 데이터베이스버전과 동일한가요? 커넥션이 열려 있는 동안에는 연결된 데이터베이스버전과 동일합니다. 하지만 커넥션닫힘 상태가 되면, 이 속성은 이후 업그레이드 트랜잭션으로 변경된 값을 반영하지 않습니다.
connection . objectStoreNames

데이터베이스 내 오브젝트 스토어의 이름들 리스트를 반환합니다.

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

지정한 nameoptions로 새로운 오브젝트 스토어를 생성하고, 새 IDBObjectStore를 반환합니다.

"InvalidStateError" DOMException (업그레이드 트랜잭션 내에서 호출되지 않은 경우) 예외를 발생시킵니다.

connection . deleteObjectStore(name)

지정한 name오브젝트 스토어를 삭제합니다.

"InvalidStateError" DOMException (업그레이드 트랜잭션 내에서 호출되지 않은 경우) 예외를 발생시킵니다.

objectStoreNames getter 단계:
  1. nameslist로, 이름 리스트는 오브젝트 스토어 각각에 대해, thisobject store set에서 구한다.

  2. names정렬된 이름 리스트 생성 결과(DOMStringList)를 반환한다.

이 값은 데이터베이스오브젝트 스토어 이름들과 동일한가요? 커넥션이 열려 있는 동안에는 연결된 데이터베이스오브젝트 스토어 이름들과 동일합니다. 하지만 커넥션닫힘 상태가 되면, 이 속성은 이후 업그레이드 트랜잭션으로 변경된 값을 반영하지 않습니다.

createObjectStore(name, options) 메서드 단계는 다음과 같습니다:

  1. databasethis의 연관된 데이터베이스로 한다.

  2. transactiondatabase업그레이드 트랜잭션으로 하고, 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. storetransaction에 연관된 새 오브젝트 스토어 핸들을 반환한다.

이 메서드는 연결된 데이터베이스에 지정한 이름으로 새 오브젝트 스토어를 생성하여 반환합니다. 이 메서드는 반드시 업그레이드 트랜잭션 내에서만 호출되어야 합니다.

이 메서드는 호출된 objectStoreNames 속성을 IDBDatabase 인스턴스에서 동기적으로 수정합니다.

일부 구현체에서는 createObjectStore() 메서드가 반환된 후 오브젝트 스토어를 생성하는 작업을 큐에 추가했지만, 이후 문제가 발생할 수 있습니다(예: 새로 만든 오브젝트 스토어의 메타데이터를 비동기로 삽입하거나, 저장소 할당량(quota) 문제로 사용자에게 권한 요청이 필요한 경우). 이런 경우에도 반드시 IDBObjectStore 객체를 생성하여 반환해야 하며, 오브젝트 스토어 생성이 실패한 것으로 판단되면, 적절한 오류로 트랜잭션을 중단하는 단계를 실행해야 합니다. 예를 들어, 할당량 문제로 오브젝트 스토어 생성에 실패했다면 QuotaExceededError 를 오류로 사용해야 합니다.

deleteObjectStore(name) 메서드 단계는 다음과 같습니다:

  1. databasethis의 연관된 데이터베이스로 한다.

  2. transactiondatabase업그레이드 트랜잭션으로 하고, null이면 throw "InvalidStateError" DOMException한다.

  3. transactionstateactive가 아니면 throw "TransactionInactiveError" DOMException한다.

  4. storedatabase오브젝트 스토어name을 가진 것으로 하고, 없으면 throw "NotFoundError" DOMException한다.

  5. storethisobject store set에서 제거한다.

  6. storetransaction에 연관된 오브젝트 스토어 핸들이 있으면, 해당 핸들의 index set에서 모든 항목을 제거한다.

  7. store를 파괴한다.

이 메서드는 연결된 데이터베이스 내에서 지정한 이름의 오브젝트 스토어를 파괴합니다. 반드시 업그레이드 트랜잭션 내에서만 호출되어야 합니다.

이 메서드는 호출된 objectStoreNames 속성을 IDBDatabase 인스턴스에서 동기적으로 수정합니다.

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

지정한 scope(단일 오브젝트 스토어 이름 또는 여러 이름 배열), mode("readonly" 또는 "readwrite"), 그리고 durability ("default", "strict" 또는 "relaxed") 옵션으로 새로운 트랜잭션을 반환합니다.

기본 mode는 "readonly"이며, 기본 durability 값은 "default"입니다.

connection . close()

모든 실행 중인 트랜잭션이 완료된 후 커넥션을 닫습니다.

transaction(storeNames, mode, options) 메서드 단계는 다음과 같습니다:

  1. 커넥션live 업그레이드 트랜잭션이 있으면, throw "InvalidStateError" DOMException한다.

  2. thisclose pending flag가 true이면 throw "InvalidStateError" DOMException한다.

  3. scopestoreNames가 시퀀스면 고유한 문자열 집합으로, 아니면 storeNames와 동일한 하나의 문자열 집합으로 한다.

  4. scope 내 어떤 문자열도 오브젝트 스토어 이름이 아니면 throw "NotFoundError" DOMException한다.

  5. scope가 비어 있으면 throw "InvalidAccessError" DOMException한다.

  6. mode가 "readonly" 또는 "readwrite"가 아니면 throw TypeError한다.

  7. transaction을 새로 생성된 트랜잭션으로 하고, 이 커넥션, mode, optionsdurability 멤버, scope에 지정된 오브젝트 스토어 집합을 사용한다.

  8. transactioncleanup event loop를 현재 이벤트 루프로 설정한다.

  9. transaction을 나타내는 IDBTransaction 객체를 반환한다.

🚧 durability 옵션은 이번 판에서 새로 추가되었습니다. Chrome 82, Edge 82, Firefox 126, Safari 15에서 지원됩니다. 🚧

참고: 생성된 transaction생명주기 규칙을 따릅니다.

close() 메서드 단계는 다음과 같습니다:

  1. 데이터베이스 커넥션 닫기를 이 커넥션에 대해 실행한다.

참고: 커넥션은 모든 미완료 트랜잭션이 완료될 때까지 실제로 닫힘 상태가 되지 않습니다. 이후 close() 호출은 효과가 없습니다.

onabort 속성은 event handler IDL attribute이며, event handler event typeabort입니다.

onclose 속성은 event handler IDL attribute이며, event handler event typeclose입니다.

onerror 속성은 event handler IDL attribute이며, event handler event typeerror입니다.

onversionchange 속성은 event handler IDL attribute이며, event handler event typeversionchange입니다.

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의 이름을 반환합니다.

store . name = newName

store의 이름newName으로 갱신합니다.

업그레이드 트랜잭션 내에서 호출되지 않으면 "InvalidStateError" DOMException 예외가 발생합니다.

store . keyPath

store의 키 경로를 반환합니다. 없으면 null입니다.

store . indexNames

store에 있는 인덱스의 이름 목록을 반환합니다.

store . transaction

연결된 트랜잭션을 반환합니다.

store . autoIncrement

store에 키 생성기가 있으면 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. name으로 오브젝트 스토어이미 존재하면, store데이터베이스에서 throw "ConstraintError" DOMException을 발생시킵니다.

  9. store이름name으로 설정합니다.

  10. this이름name으로 설정합니다.

keyPath getter 단계는 this오브젝트 스토어키 경로를 반환하거나, 없으면 null을 반환합니다. 키 경로DOMString (문자열인 경우) 또는 sequence<DOMString> (문자열 목록인 경우)로 변환됩니다. 자세한 내용은 [WEBIDL]을 참고하세요.

NOTE: 반환된 값은 오브젝트 스토어가 생성될 때 사용된 인스턴스와 동일하지 않습니다. 단, 해당 속성이 객체(특히 Array)를 반환할 경우, 매번 동일한 객체 인스턴스를 반환합니다. 객체의 속성을 변경해도 오브젝트 스토어에는 영향을 주지 않습니다.

indexNames getter 단계는 다음과 같습니다:
  1. names리스트로 설정합니다. 이 리스트는 이름들의 모음이며, 인덱스들이 thisindex set에 포함되어 있습니다.

  2. names정렬된 이름 목록 생성의 결과(DOMStringList)를 반환합니다.

이것이 오브젝트 스토어인덱스 이름 목록과 같은가요? 트랜잭션끝나지 않은 한, 이는 연결된 오브젝트 스토어인덱스 이름 목록과 같습니다. 하지만 트랜잭션끝나면 이후 업그레이드 트랜잭션에서 변경된 내용은 반영되지 않습니다.

transaction getter 단계는 this트랜잭션을 반환하는 것입니다.

autoIncrement getter 단계는 this오브젝트 스토어키 생성기가 있으면 true, 없으면 false를 반환하는 것입니다.

다음 메서드는 "ReadOnlyError" DOMException 예외를 발생시키며, 읽기 전용 트랜잭션 내에서 호출될 경우 발생합니다. 또한, 트랜잭션active가 아닐 때 호출되면 "TransactionInactiveError" DOMException 예외가 발생합니다.
request = store . put(value [, key])
request = store . add(value [, key])

지정된 valuekey레코드를 store에 추가하거나 갱신합니다.

store가 인라인 키를 사용할 때 key가 지정되면 "DataError" DOMException 예외가 발생합니다.

put() 를 사용하면 기존 레코드 기준으로 대체됩니다. add() 를 사용하면, 레코드가 이미 해당 로 존재할 경우 request는 실패하며, requesterror 속성이 "ConstraintError" DOMException으로 설정됩니다.

성공 시 requestresult 값은 레코드가 됩니다.

request = store . delete(query)

store에서 지정된 또는 키 범위에 해당하는 레코드를 삭제합니다.

성공 시 requestresult 값은 undefined가 됩니다.

request = store . clear()

store의 모든 레코드를 삭제합니다.

성공 시 requestresult 값은 undefined가 됩니다.

put(value, key) 메서드 단계는 add or putthis, value, key 그리고 no-overwrite flag를 false로 하여 실행한 결과를 반환하는 것입니다.

add(value, key) 메서드 단계는 add or putthis, value, key 그리고 no-overwrite flag를 true로 하여 실행한 결과를 반환하는 것입니다.

add or puthandle, value, key, no-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로 실행하여 얻습니다. 예외가 발생하면 다시 throw 합니다.

    2. r이 "invalid value" 또는 "invalid type"이면, throw "DataError" DOMException을 발생시킵니다.

    3. keyr로 설정합니다.

  9. targetRealm을 user-agent가 정의하는 Realm으로 설정합니다.

  10. clonetransactiontargetRealm에서 value복제로 설정합니다. 예외가 발생하면 다시 throw 합니다.

    왜 값을 복제하나요? 값은 저장될 때 직렬화됩니다. 여기서 복제본으로 다루는 것은 이 명세의 다른 알고리듬들이 ECMAScript 값으로 다루도록 하기 위함입니다. 단, 구현체는 행동 차이가 관찰되지 않는 한 최적화할 수 있습니다.
  11. store인라인 키를 사용하면:

    1. kpk키 경로를 이용해 값에서 키 추출 알고리듬을 clonestore키 경로로 실행하여 얻습니다. 예외가 발생하면 다시 throw 합니다.

    2. kpk가 invalid이면, throw "DataError" DOMException을 발생시킵니다.

    3. kpk가 실패가 아니면 keykpk로 설정합니다.

    4. 그 외(kpk가 실패):

      1. store키 생성기가 없으면, throw "DataError" DOMException을 발생시킵니다.

      2. 키가 값에 주입될 수 있는지 확인 알고리듬을 clonestore키 경로로 실행하여 false가 나오면, throw "DataError" DOMException을 발생시킵니다.

  12. operation오브젝트 스토어에 레코드 저장 알고리듬을 store, clone, key, no-overwrite flag로 실행하는 알고리듬으로 설정합니다.

  13. handleoperation으로 요청을 비동기적으로 실행 알고리듬을 실행한 결과(IDBRequest)를 반환합니다.

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로 실행한 결과로 설정합니다. 예외가 발생하면 다시 throw 합니다.

  7. operation오브젝트 스토어에서 레코드 삭제 알고리듬을 storerange로 실행하는 알고리듬으로 설정합니다.

  8. thisoperation으로 요청을 비동기적으로 실행 알고리듬을 실행한 결과(IDBRequest)를 반환합니다.

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. thisoperation으로 요청을 비동기적으로 실행 알고리듬을 실행한 결과(IDBRequest)를 반환합니다.

다음 메서드들은 트랜잭션active가 아닐 때 호출하면 "TransactionInactiveError" DOMException 예외가 발생합니다.
request = store . get(query)

지정된 또는 키 범위에 맞는 첫 번째 레코드을 가져옵니다.

성공 시 requestresult 값은 이거나, 일치하는 레코드가 없으면 undefined입니다.

request = store . getKey(query)

지정된 또는 키 범위에 맞는 첫 번째 레코드를 가져옵니다.

성공 시 requestresult 값은 이거나, 일치하는 레코드가 없으면 undefined입니다.

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

지정된 또는 키 범위에 맞는 레코드들을 가져옵니다(옵션 count까지). direction 옵션을 "next"로 설정하면 처음 count개의 값, "prev"로 설정하면 마지막 count개의 값을 반환합니다.

성공 시 requestresult 값은 들의 Array입니다.

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

지정된 또는 키 범위에 맞는 레코드들을 가져옵니다(옵션 count까지). direction 옵션을 "next"로 설정하면 처음 count개의 키, "prev"로 설정하면 마지막 count개의 키를 반환합니다.

성공 시 requestresult 값은 들의 Array입니다.

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

레코드을 가져옵니다.

query 옵션은 매칭할 또는 키 범위를 지정합니다. count 옵션은 일치하는 레코드 수를 제한합니다. direction 옵션을 "next"로 설정하면 처음 count개의 레코드, "prev"로 설정하면 마지막 count개의 레코드를 반환합니다.

성공 시 requestresult 값은 각 멤버가 IDBRecordArray입니다.

request = store . count(query)

지정된 또는 키 범위에 맞는 레코드의 개수를 가져옵니다.

성공 시 requestresult 값은 개수입니다.

get(query) 메서드 단계는 다음과 같습니다:

  1. transactionthis트랜잭션으로 설정합니다.

  2. storethis오브젝트 스토어로 설정합니다.

  3. store가 삭제된 경우, throw "InvalidStateError" DOMException을 발생시킵니다.

  4. transaction상태active가 아니면, throw "TransactionInactiveError" DOMException을 발생시킵니다.

  5. range값을 키 범위로 변환 알고리듬을 query와 true로 실행한 결과로 설정합니다. 예외가 발생하면 다시 throw 합니다.

  6. operation오브젝트 스토어에서 값 가져오기 알고리듬을 현재 Realm 레코드, store, range로 실행하는 알고리듬으로 설정합니다.

  7. thisoperation으로 요청을 비동기적으로 실행 알고리듬을 실행한 결과(IDBRequest)를 반환합니다.

참고: 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로 실행한 결과로 설정합니다. 예외가 발생하면 다시 throw 합니다.

  6. operation오브젝트 스토어에서 키 가져오기 알고리듬을 storerange로 실행하는 알고리듬으로 설정합니다.

  7. thisoperation으로 요청을 비동기적으로 실행 알고리듬을 실행한 결과(IDBRequest)를 반환합니다.

참고: query 매개변수는 또는 키 범위(IDBKeyRange)가 될 수 있으며, 가져올 레코드의 키를 식별합니다. 범위가 지정된 경우, 해당 범위에 존재하는 첫 번째 키를 가져옵니다.

getAll(queryOrOptions, count) 메서드 단계는 다음과 같습니다:

  1. 여러 항목을 가져오는 요청 생성 알고리듬을 현재 Realm 레코드, this, "value", queryOrOptions, count(있으면)로 실행한 결과를 반환합니다. 예외가 발생하면 다시 throw 합니다.

getAllKeys(queryOrOptions, count) 메서드 단계는 다음과 같습니다:

  1. 여러 항목을 가져오는 요청 생성 알고리듬을 현재 Realm 레코드, this, "key", queryOrOptions, count(있으면)로 실행한 결과를 반환합니다. 예외가 발생하면 다시 throw 합니다.

getAllRecords(options) 메서드 단계는 다음과 같습니다:

  1. 여러 항목을 가져오는 요청 생성 알고리듬을 현재 Realm 레코드, this, "record", options로 실행한 결과를 반환합니다. 예외가 발생하면 다시 throw 합니다.

count(query) 메서드 단계는 다음과 같습니다:

  1. transactionthis트랜잭션으로 설정합니다.

  2. storethis오브젝트 스토어로 설정합니다.

  3. store가 삭제된 경우, throw "InvalidStateError" DOMException을 발생시킵니다.

  4. transaction상태active가 아니면, throw "TransactionInactiveError" DOMException을 발생시킵니다.

  5. range값을 키 범위로 변환 알고리듬을 query로 실행한 결과로 설정합니다. 예외가 발생하면 다시 throw 합니다.

  6. operation범위 내 레코드 개수 세기 알고리듬을 storerange로 실행하는 알고리듬으로 설정합니다.

  7. thisoperation으로 요청을 비동기적으로 실행 알고리듬을 실행한 결과(IDBRequest)를 반환합니다.

참고: query 매개변수는 또는 키 범위(IDBKeyRange)가 될 수 있으며, 개수를 셀 레코드를 식별합니다. null 또는 생략된 경우 제한 없는 키 범위가 사용됩니다.

다음 메서드들은 트랜잭션active가 아닐 때 호출하면 "TransactionInactiveError" DOMException 예외가 발생합니다.
request = store . openCursor([query [, direction = "next"]])

query에 맞는 레코드들에 대해 direction 순서로 커서를 엽니다. query가 null이면 store의 모든 레코드가 매칭됩니다.

성공 시 requestresult 값은 IDBCursorWithValue 이며, 첫 번째로 매칭된 레코드를 가리키거나, 매칭되는 레코드가 없으면 null입니다.

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

query에 맞는 레코드들에 대해 direction 순서로 커서를 엽니다. key only flag가 true로 설정되어 있습니다. query가 null이면 store의 모든 레코드가 매칭됩니다.

성공 시 requestresult 값은 IDBCursor 이며, 첫 번째로 매칭된 레코드를 가리키거나, 매칭되는 레코드가 없으면 null입니다.

openCursor(query, direction) 메서드 단계는 다음과 같습니다:

  1. transactionthis트랜잭션으로 설정합니다.

  2. storethis오브젝트 스토어로 설정합니다.

  3. store가 삭제된 경우, throw "InvalidStateError" DOMException을 발생시킵니다.

  4. transaction상태active가 아니면, throw "TransactionInactiveError" DOMException을 발생시킵니다.

  5. range값을 키 범위로 변환 알고리듬을 query로 실행한 결과로 설정합니다. 예외가 발생하면 다시 throw 합니다.

  6. cursor를 새로운 커서로 생성하며, source handlethis로, position은 undefined로, directiondirection으로, got value flag는 false로, keyvalue는 undefined로, rangerange로, key only flag는 false로 설정합니다.

  7. operation커서를 반복 알고리듬을 현재 Realm 레코드, cursor로 실행하는 알고리듬으로 설정합니다.

  8. request요청을 비동기적으로 실행 알고리듬을 this, operation으로 실행한 결과로 설정합니다.

  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로 실행한 결과로 설정합니다. 예외가 발생하면 다시 throw 합니다.

  6. cursor를 새로운 커서로 생성하며, source handlethis로, position은 undefined로, directiondirection으로, got value flag는 false로, keyvalue는 undefined로, rangerange로, key only flag는 true로 설정합니다.

  7. operation커서를 반복 알고리듬을 현재 Realm 레코드, cursor로 실행하는 알고리듬으로 설정합니다.

  8. request요청을 비동기적으로 실행 알고리듬을 this, operation으로 실행한 결과로 설정합니다.

  9. cursorrequestrequest로 설정합니다.

  10. request를 반환합니다.

참고: query 매개변수는 또는 키 범위(IDBKeyRange)가 될 수 있으며, 커서범위로 사용됩니다. null 또는 생략된 경우 제한 없는 키 범위가 사용됩니다.

index = store . index(name)

store에서 name이라는 이름의 인덱스에 대한 IDBIndex를 반환합니다.

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

store에 주어진 name, keyPath, options으로 새로운 인덱스를 생성하고 새로운 IDBIndex를 반환합니다. 만약 keyPathoptionsstore에 이미 있는 데이터와 맞지 않는 제약 조건을 정의하면 업그레이드 트랜잭션이 "ConstraintError" DOMException과 함께 중단(abort)됩니다.

업그레이드 트랜잭션 내에서 호출하지 않으면 "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로, unique flagunique로, multiEntry flagmultiEntry로 설정합니다.

  12. indexthisindex set에 추가합니다.

  13. indexthis에 연결된 새로운 index handle을 반환합니다.

이 메서드는 오브젝트 스토어에 주어진 이름으로 새로운 인덱스를 생성하여 반환합니다. 이 메서드는 반드시 업그레이드 트랜잭션 내에서만 호출되어야 합니다.

생성 요청된 인덱스는 인덱스의 키 경로 값의 유일성 등 인덱스가 참조하는 오브젝트 스토어 데이터에 대한 제약 조건을 가질 수 있습니다. 만약 참조된 오브젝트 스토어에 이미 제약 조건을 위반하는 데이터가 있어도 createIndex() 구현에서 예외를 던지거나 반환값에 영향을 주면 안 됩니다. 구현은 반드시 IDBIndex 객체를 생성 및 반환하며, 데이터베이스 작업을 큐잉하여 해당 createIndex() 호출에 사용된 업그레이드 트랜잭션을 중단(abort)해야 합니다.

이 메서드는 호출된 IDBObjectStore 인스턴스의 indexNames 속성을 동기적으로 수정합니다. 비록 이 메서드는 IDBRequest 객체를 반환하지 않지만, 인덱스 생성 자체는 업그레이드 트랜잭션 내에서 비동기 요청으로 처리됩니다.

일부 구현에서는 createIndex 메서드가 반환된 이후에 인덱스 생성이 비동기적으로 실패하는 경우가 있을 수 있습니다. 예를 들어, 새로 생성된 인덱스의 메타데이터가 데이터베이스에 비동기적으로 삽입되거나, 할당량(quota) 문제로 사용자에게 권한을 요청해야 하는 경우 등이 이에 해당합니다. 이러한 경우에도 반드시 IDBIndex 객체를 생성 및 반환해야 하며, 인덱스 생성에 실패하면 적절한 오류와 함께 트랜잭션 중단(abort) 단계로 진행해야 합니다. 예를 들면, 할당량 초과로 인덱스 생성이 실패하면 QuotaExceededError를 오류로 사용하고, unique flag 제약 조건으로 인덱스 생성이 불가하면 "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() 를 호출한 시점에는 두 요청이 모두 실행되지 않은 상태입니다. 두 번째 요청이 실행되면 중복된 name이 생성됩니다. 인덱스 생성은 비동기 요청으로 간주되므로, 인덱스의 유일성 제약 조건이 두 번째 요청의 실패 원인이 되지 않습니다. 대신, 인덱스가 생성되고 제약 조건이 위반되면 트랜잭션중단(abort)됩니다.

index(name) 메서드 단계는 다음과 같습니다:

  1. transactionthis트랜잭션으로 설정합니다.

  2. storethis오브젝트 스토어로 설정합니다.

  3. store가 삭제된 경우, throw "InvalidStateError" DOMException을 발생시킵니다.

  4. transaction상태finished이면, throw "InvalidStateError" DOMException을 발생시킵니다.

  5. indexindex set에서 name 이름의 인덱스로 설정합니다. 없으면 throw "NotFoundError" DOMException을 발생시킵니다.

  6. indexthis에 연결된 index handle을 반환합니다.

참고: 동일한 IDBObjectStore 인스턴스에서 같은 이름으로 이 메서드를 여러 번 호출하면 같은 IDBIndex 인스턴스를 반환합니다.

참고: 반환된 IDBIndex 인스턴스는 해당 IDBObjectStore 인스턴스에만 특화되어 있습니다. 다른 IDBObjectStore 인스턴스에서 같은 이름으로 호출하면 다른 IDBIndex 인스턴스를 반환합니다.

deleteIndex(name) 메서드 단계는 다음과 같습니다:

  1. transactionthis트랜잭션으로 설정합니다.

  2. storethis오브젝트 스토어로 설정합니다.

  3. transaction업그레이드 트랜잭션이 아니면, throw "InvalidStateError" DOMException을 발생시킵니다.

  4. store가 삭제된 경우, throw "InvalidStateError" DOMException을 발생시킵니다.

  5. transaction상태active가 아니면, throw "TransactionInactiveError" DOMException을 발생시킵니다.

  6. indexstore에서 name 이름의 인덱스로 설정합니다. 없으면 throw "NotFoundError" DOMException을 발생시킵니다.

  7. indexthisindex set에서 제거합니다.

  8. index를 파기(destroy)합니다.

이 메서드는 오브젝트 스토어에 주어진 이름의 인덱스를 파기(destroy)합니다. 이 메서드는 반드시 업그레이드 트랜잭션 내에서만 호출되어야 합니다.

이 메서드는 호출된 IDBObjectStore 인스턴스의 indexNames 속성을 동기적으로 수정합니다. 비록 이 메서드는 IDBRequest 객체를 반환하지 않지만, 인덱스 파기(destroy) 자체는 업그레이드 트랜잭션 내에서 비동기 요청으로 처리됩니다.

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

인덱스의 이름을 반환합니다.

index . name = newName

저장소의 이름newName으로 업데이트합니다.

"InvalidStateError" DOMException 을 던집니다. 업그레이드 트랜잭션 내에서 호출되지 않은 경우에 발생합니다.

index . objectStore

인덱스가 속한 IDBObjectStore를 반환합니다.

index . keyPath

인덱스의 키 경로를 반환합니다.

index . multiEntry

인덱스의 multiEntry 플래그가 true인 경우 true를 반환합니다.

index . unique

인덱스의 unique 플래그가 true인 경우 true를 반환합니다.

name getter 단계는 this이름을 반환하는 것입니다.

이게 인덱스이름과 동일한가요? 트랜잭션종료되지 않는 한, 이는 연결된 인덱스이름과 동일합니다. 그러나 트랜잭션종료되면, 이 속성은 이후 업그레이드 트랜잭션으로 변경된 내용을 반영하지 않습니다.

name setter 단계는 다음과 같습니다:

  1. namethe given value를 할당합니다.

  2. transactionthistransaction을 할당합니다.

  3. indexthisindex를 할당합니다.

  4. transactionupgrade transaction이 아니면, throw "InvalidStateError" DOMException 오류를 발생시킵니다.

  5. transactionstateactive가 아니면, throw "TransactionInactiveError" DOMException 오류를 발생시킵니다.

  6. index 또는 indexobject store가 삭제된 경우, throw "InvalidStateError" DOMException 오류를 발생시킵니다.

  7. indexnamename과 같으면, 이 단계를 종료합니다.

  8. name으로 index named가 이미 indexobject store에 존재하면, throw "ConstraintError" DOMException 오류를 발생시킵니다.

  9. indexnamename으로 설정합니다.

  10. thisnamename으로 설정합니다.

objectStore getter 단계는 thisobject store handle을 반환합니다.

keyPath getter 단계는 thisindexkey path를 반환합니다. key pathDOMString (문자열일 경우) 또는 sequence<DOMString> (문자열 리스트일 경우)로 변환됩니다. 자세한 내용은 [WEBIDL]를 참고하세요.

참고: 반환된 값은 index가 생성될 때 사용된 인스턴스와 동일하지 않습니다. 하지만 이 속성이 객체(특히 Array)를 반환하는 경우, 검사할 때마다 동일한 객체 인스턴스를 반환합니다. 객체의 프로퍼티를 변경해도 index에는 영향을 주지 않습니다.

multiEntry getter 단계는 thisindexmultiEntry flag를 반환합니다.

unique getter 단계는 thisindexunique flag를 반환합니다.

다음 메서드는 "TransactionInactiveError" DOMException 오류를 발생시킵니다. transactionactive가 아닐 때 호출하면 발생합니다.
request = index . get(query)

주어진 key 또는 key range와 일치하는 첫 번째 recordvalue를 가져옵니다.

성공하면 requestresult 값은 value가 되고, 일치하는 record가 없으면 undefined입니다.

request = index . getKey(query)

주어진 key 또는 key range와 일치하는 첫 번째 recordkey를 가져옵니다.

성공하면 requestresult 값은 key가 되고, 일치하는 record가 없으면 undefined입니다.

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

주어진 key 또는 key range와 일치하는 recordsvalues를 가져옵니다. (count가 있으면 최대 count개까지) direction 옵션을 "next" 로 설정하면 첫 count개의 값을, "prev" 로 설정하면 마지막 count개의 값을 반환합니다. direction 옵션을 "nextunique" 또는 "prevunique" 로 설정하면 중복된 인덱스 키가 있는 레코드는 첫 번째 레코드만 가져오고 이후 중복은 제외합니다.

성공하면 requestresult 값은 Array 형태의 values가 됩니다.

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

주어진 key 또는 key range와 일치하는 recordskeys를 가져옵니다. (count가 있으면 최대 count개까지) direction 옵션을 "next" 로 설정하면 첫 count개의 키를, "prev" 로 설정하면 마지막 count개의 키를 반환합니다. direction 옵션을 "nextunique" 또는 "prevunique" 로 설정하면 중복된 인덱스 키가 있는 레코드는 첫 번째 레코드만 가져오고 이후 중복은 제외합니다.

성공하면 requestresult 값은 Array 형태의 keys가 됩니다.

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

recordskeys, values, 그리고 인덱스 keys를 가져옵니다.

query 옵션은 일치시킬 key 또는 key range를 지정합니다. count 옵션은 일치시키는 레코드의 수를 제한합니다. direction 옵션을 "next" 로 설정하면 첫 count개의 레코드를, "prev" 로 설정하면 마지막 count개의 레코드를 반환합니다. direction 옵션을 "nextunique" 또는 "prevunique" 로 설정하면 중복된 인덱스 키가 있는 레코드는 첫 번째 레코드만 가져오고 이후 중복은 제외합니다.

성공하면 requestresult 값은 Array 형태이며, 각 멤버는 IDBRecord입니다. IDBRecord의 key 를 사용하여 해당 레코드의 인덱스 key를 얻을 수 있습니다. IDBRecord의 primaryKey 를 사용하여 해당 레코드의 key를 얻을 수 있습니다.

request = index . count(query)

주어진 key 또는 key range와 일치하는 records의 개수를 가져옵니다.

성공하면 requestresult 값은 해당 개수(count)입니다.

get(query) 메서드 단계는 다음과 같습니다:

  1. transactionthistransaction을 할당합니다.

  2. indexthisindex를 할당합니다.

  3. index 또는 indexobject store가 삭제된 경우, throw "InvalidStateError" DOMException 오류를 발생시킵니다.

  4. transactionstateactive가 아니면, throw "TransactionInactiveError" DOMException 오류를 발생시킵니다.

  5. rangeconvert a value to a key range의 결과를 query와 true로 호출하여 할당합니다. 예외가 발생하면 재throw합니다.

  6. operationretrieve a referenced value from an indexthe current Realm record, index, range와 함께 실행하는 알고리즘을 할당합니다.

  7. asynchronously execute a requestthisoperation을 사용하여 실행한 결과(IDBRequest)를 반환합니다.

참고: query 파라미터는 key 또는 key range(IDBKeyRange)일 수 있으며, 가져올 referenced value를 식별합니다. 범위를 지정하면, 해당 범위 내에서 첫 번째로 존재하는 레코드를 가져옵니다.

참고: 주어진 key에 해당하는 레코드가 없을 때와, 해당 key의 레코드 값이 undefined인 경우 결과는 동일합니다. 두 상황을 구분하려면 동일한 key로 openCursor() 를 사용할 수 있습니다. 이 경우 레코드가 존재하면 값이 undefined인 커서를 반환하며, 레코드가 없으면 커서 자체가 반환되지 않습니다.

getKey(query) 메서드 단계는 다음과 같습니다:

  1. transactionthistransaction을 할당합니다.

  2. indexthisindex를 할당합니다.

  3. index 또는 indexobject store가 삭제된 경우, throw "InvalidStateError" DOMException 오류를 발생시킵니다.

  4. transactionstateactive가 아니면, throw "TransactionInactiveError" DOMException 오류를 발생시킵니다.

  5. rangeconvert a value to a key range의 결과를 query와 true로 호출하여 할당합니다. 예외가 발생하면 재throw합니다.

  6. operationretrieve a value from an indexindexrange와 함께 실행하는 알고리즘을 할당합니다.

  7. asynchronously execute a requestthisoperation을 사용하여 실행한 결과(IDBRequest)를 반환합니다.

참고: query 파라미터는 key 또는 key range(IDBKeyRange)일 수 있으며, 가져올 record의 key를 식별합니다. 범위를 지정하면, 해당 범위 내에서 첫 번째로 존재하는 key를 가져옵니다.

getAll(queryOrOptions, count) 메서드 단계는 다음과 같습니다:

  1. 여러 항목을 검색하는 요청 생성현재 Realm 레코드, this, "value", queryOrOptions, 그리고 count가 주어졌다면 count와 함께 실행한 결과를 반환합니다. 예외가 발생하면 다시 throw합니다.

getAllKeys(queryOrOptions, count) 메서드 단계는 다음과 같습니다:

  1. 여러 항목을 검색하는 요청 생성현재 Realm 레코드, this, "key", queryOrOptions, 그리고 count가 주어졌다면 count와 함께 실행한 결과를 반환합니다. 예외가 발생하면 다시 throw합니다.

getAllRecords(options) 메서드 단계는 다음과 같습니다:

  1. 여러 항목을 검색하는 요청 생성현재 Realm 레코드, this, "record", 그리고 options와 함께 실행한 결과를 반환합니다. 예외가 발생하면 다시 throw합니다.

count(query) 메서드 단계는 다음과 같습니다:

  1. transactionthistransaction을 할당합니다.

  2. indexthisindex를 할당합니다.

  3. index 또는 indexobject store가 삭제된 경우, throw "InvalidStateError" DOMException 오류를 발생시킵니다.

  4. transactionstateactive가 아니면, throw "TransactionInactiveError" DOMException 오류를 발생시킵니다.

  5. range값을 키 범위로 변환의 결과를 query로 호출하여 할당합니다. 예외가 발생하면 다시 throw합니다.

  6. operation범위 내 레코드 개수 세기indexrange로 실행하는 알고리즘을 할당합니다.

  7. 비동기적으로 요청 실행thisoperation을 사용하여 실행한 결과(IDBRequest)를 반환합니다.

참고: query 파라미터는 key 또는 key range(IDBKeyRange)일 수 있으며, 카운트할 records를 식별합니다. null이거나 지정되지 않으면, 제한 없는 키 범위가 사용됩니다.

다음 메서드는 트랜잭션active 상태가 아닐 때 "TransactionInactiveError" DOMException을 던집니다.
request = index . openCursor([query [, direction = "next"]])

query에 일치하는 레코드들을 direction 순서로 커서로 엽니다. query가 null이면, index의 모든 레코드가 일치합니다.

성공하면 requestresultIDBCursorWithValue 이거나, 일치하는 레코드가 없으면 null입니다.

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

키 전용 플래그가 true로 설정된 커서query에 일치하는 레코드들에 대해 direction 순서로 엽니다. query가 null이면, index의 모든 레코드가 일치합니다.

성공하면 requestresultIDBCursor 이거나, 일치하는 레코드가 없으면 null입니다.

openCursor(query, direction) 메서드 단계는 다음과 같습니다:

  1. transactionthistransaction으로 설정한다.

  2. indexthisindex로 설정한다.

  3. index 또는 indexobject store가 삭제된 경우, throw "InvalidStateError" DOMException을 발생시킨다.

  4. transactionstateactive가 아니면, throw "TransactionInactiveError" DOMException을 발생시킨다.

  5. range값을 키 범위로 변환하기의 결과로 query를 사용하여 설정한다. 예외가 발생하면 다시 던진다.

  6. cursor를 새로운 cursor로 생성하고, source handlethis로, position은 undefined로, directiondirection으로, got value flag는 false로, keyvalue는 undefined로, rangerange로, key only flag는 false로 설정한다.

  7. operation커서를 반복하기현재 Realm recordcursor로 실행하는 알고리즘으로 설정한다.

  8. request요청을 비동기로 실행하기thisoperation으로 실행한 결과로 설정한다.

  9. cursorrequestrequest로 설정한다.

  10. request를 반환한다.

NOTE: query 매개변수는 key 또는 key range (IDBKeyRange) 를 cursorrange로 사용할 수 있습니다. null이거나 지정되지 않은 경우, 제한 없는 키 범위가 사용됩니다.

openKeyCursor(query, direction) 메서드 단계는 다음과 같습니다:

  1. transactionthistransaction으로 설정한다.

  2. indexthisindex로 설정한다.

  3. index 또는 indexobject store가 삭제된 경우, throw "InvalidStateError" DOMException을 발생시킨다.

  4. transactionstateactive가 아니면, throw "TransactionInactiveError" DOMException을 발생시킨다.

  5. range값을 키 범위로 변환하기의 결과로 query를 사용하여 설정한다. 예외가 발생하면 다시 던진다.

  6. cursor를 새로운 cursor로 생성하고, source handlethis로, position은 undefined로, directiondirection으로, got value flag는 false로, keyvalue는 undefined로, rangerange로, key only flag는 true로 설정한다.

  7. operation커서를 반복하기현재 Realm recordcursor로 실행하는 알고리즘으로 설정한다.

  8. request요청을 비동기로 실행하기thisoperation으로 실행한 결과로 설정한다.

  9. cursorrequestrequest로 설정한다.

  10. request를 반환한다.

NOTE: query 매개변수는 key 또는 key range (IDBKeyRange) 를 cursorrange로 사용할 수 있습니다. 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 getter 단계는 키를 값으로 변환하기의 결과를 this하한에 대해 반환합니다. null이 아니면 반환하고, 아니면 undefined를 반환합니다.

upper getter 단계는 키를 값으로 변환하기의 결과를 this상한에 대해 반환합니다. null이 아니면 반환하고, 아니면 undefined를 반환합니다.

lowerOpen getter 단계는 this하한 개방 플래그를 반환합니다.

upperOpen getter 단계는 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가 "invalid value" 또는 "invalid type"이면, 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가 "invalid value" 또는 "invalid type"이면, throw "DataError" DOMException을 발생시킨다.

  3. 새로운 키 범위를 생성하여 하한을 null로, 하한 개방 플래그를 true로, 상한upperKey로, 상한 개방 플래그open으로 설정하여 반환한다.

bound(lower, upper, lowerOpen, upperOpen) 메서드 단계는 다음과 같습니다:

  1. lowerKey값을 키로 변환하기의 결과로 lower를 사용하여 얻는다. 예외가 발생하면 다시 던진다.

  2. lowerKey가 "invalid value" 또는 "invalid type"이면, throw "DataError" DOMException을 발생시킨다.

  3. upperKey값을 키로 변환하기의 결과로 upper를 사용하여 얻는다. 예외가 발생하면 다시 던진다.

  4. upperKey가 "invalid value" 또는 "invalid type"이면, 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가 "invalid value" 또는 "invalid type"이면, 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 getter 단계는 키를 값으로 변환하기의 결과를 this로 반환합니다.

primaryKey getter 단계는 키를 값으로 변환하기의 결과를 this주요 키로 반환합니다.

value getter 단계는 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 getter 단계는 this소스 핸들을 반환합니다.

NOTE: source 속성은 커서가 현재 반복 중이거나, 끝까지 반복되었거나, 트랜잭션활성 상태가 아니더라도 절대 null을 반환하거나 예외를 발생시키지 않습니다.

direction getter 단계는 this방향을 반환합니다.

key getter 단계는 커서의 현재 키를 값으로 변환하기의 결과를 반환합니다.

NOTE: key 가 객체(예: Date 또는 Array)를 반환하는 경우, 커서의 가 변경되지 않는 한, 매번 같은 객체 인스턴스를 반환합니다. 객체가 수정되면 커서 값을 확인하는 모든 사람에게 수정 사항이 보입니다. 하지만 이러한 객체를 수정해도 데이터베이스 내용은 변경되지 않습니다.

primaryKey getter 단계는 커서의 현재 실효 키키를 값으로 변환하기의 결과를 반환합니다.

NOTE: primaryKey 가 객체(예: Date 또는 Array)를 반환하는 경우, 커서의 실효 키가 변경되지 않는 한, 매번 같은 객체 인스턴스를 반환합니다. 객체가 수정되면 커서 값을 확인하는 모든 사람에게 수정 사항이 보입니다. 하지만 이러한 객체를 수정해도 데이터베이스 내용은 변경되지 않습니다.

request getter 단계는 this요청을 반환합니다.

🚧 request 속성은 이 판에서 새로 추가되었습니다. Chrome 76, Edge 79, Firefox 77, Safari 15에서 지원됩니다. 🚧
다음 메서드들은 커서를 이동시킵니다. 커서가 이동된 후, success 이벤트가 커서가 열릴 때 반환된 동일한 IDBRequest 에서 발생합니다. result 는 범위 내에 레코드가 있으면 같은 커서이고, 그렇지 않으면 undefined입니다.

커서가 이미 이동 중일 때 호출하면, "InvalidStateError" DOMException이 발생합니다.

다음 메서드들은 트랜잭션활성 상태가 아닐 때 호출되면 "TransactionInactiveError" DOMException을 발생시킵니다.

cursor . advance(count)

커서를 범위 내 다음 count개의 레코드까지 이동시킵니다.

cursor . continue()

커서를 범위 내 다음 레코드로 이동시킵니다.

cursor . continue(key)

커서를 범위 내 key와 일치하거나 그 이후의 레코드로 이동시킵니다.

cursor . continuePrimaryKey(key, primaryKey)

커서를 범위 내 keyprimaryKey와 일치하거나 그 이후의 레코드로 이동시킵니다. 소스인덱스가 아닌 경우에는 "InvalidAccessError" DOMException이 발생합니다.

advance(count) 메서드 단계는 다음과 같습니다:

  1. count가 0이면, throw TypeError를 발생시킨다.

  2. transactionthis트랜잭션으로 설정한다.

  3. transaction상태활성이 아니면, throw "TransactionInactiveError" DOMException을 발생시킨다.

  4. this소스 또는 실효 오브젝트 스토어가 삭제된 경우, 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 record, this, count로 실행한다.

  11. 요청 비동기 실행하기this소스 핸들, operation, request로 실행한다.

NOTE: 새 커서 데이터가 로드되기 전 이 메서드를 두 번 이상 호출하면(예: 같은 onsuccess 핸들러 내에서 advance() 를 두 번 호출하면) 두 번째 호출 시 "InvalidStateError" DOMException 이 발생합니다. 이는 커서의 got value flag가 false로 설정되었기 때문입니다.

continue(key) 메서드 단계는 다음과 같습니다:

  1. transactionthis트랜잭션으로 설정한다.

  2. transaction상태활성이 아니면, throw "TransactionInactiveError" DOMException을 발생시킨다.

  3. this소스 또는 실효 오브젝트 스토어가 삭제된 경우, throw "InvalidStateError" DOMException을 발생시킨다.

  4. thisgot value flag가 false이면(커서가 반복 중이거나 끝까지 반복된 경우), throw "InvalidStateError" DOMException을 발생시킨다.

  5. key가 주어지면:

    1. r값을 키로 변환하기의 결과로 key를 사용하여 얻는다. 예외가 발생하면 다시 던진다.

    2. r이 "invalid value" 또는 "invalid type"이면, throw "DataError" DOMException을 발생시킨다.

    3. keyr로 설정한다.

    4. key보다 작거나 같으면 this포지션이고, this방향이 "next" 또는 "nextunique"이면, throw "DataError" DOMException을 발생시킨다.

    5. key보다 크거나 같으면 this포지션이고, this방향이 "prev" 또는 "prevunique"이면, throw "DataError" DOMException을 발생시킨다.

  6. thisgot value flag를 false로 설정한다.

  7. requestthisrequest로 설정한다.

  8. requestprocessed flag를 false로 설정한다.

  9. requestdone flag를 false로 설정한다.

  10. operation커서 반복하기 알고리즘으로, 현재 Realm record, this, key(있으면)로 실행한다.

  11. 요청 비동기 실행하기this소스 핸들, operation, request로 실행한다.

NOTE: 새 커서 데이터가 로드되기 전 이 메서드를 두 번 이상 호출하면(예: 같은 onsuccess 핸들러 내에서 continue() 를 두 번 호출하면) 두 번째 호출 시 "InvalidStateError" DOMException 이 발생합니다. 이는 커서의 got value flag가 false로 설정되었기 때문입니다.

continuePrimaryKey(key, primaryKey) 메서드 단계는 다음과 같습니다:

  1. transactionthis트랜잭션으로 설정한다.

  2. transaction상태활성이 아니면, throw "TransactionInactiveError" DOMException을 발생시킨다.

  3. this소스 또는 실효 오브젝트 스토어가 삭제된 경우, throw "InvalidStateError" DOMException을 발생시킨다.

  4. this소스인덱스가 아니면, throw "InvalidAccessError" DOMException을 발생시킨다.

  5. this방향이 "next" 또는 "prev"가 아니면, throw "InvalidAccessError" DOMException을 발생시킨다.

  6. thisgot value flag가 false이면(커서가 반복 중이거나 끝까지 반복된 경우), throw "InvalidStateError" DOMException을 발생시킨다.

  7. r값을 키로 변환하기의 결과로 key를 사용하여 얻는다. 예외가 발생하면 다시 던진다.

  8. r이 "invalid value" 또는 "invalid type"이면, throw "DataError" DOMException을 발생시킨다.

  9. keyr로 설정한다.

  10. r값을 키로 변환하기의 결과로 primaryKey를 사용하여 얻는다. 예외가 발생하면 다시 던진다.

  11. r이 "invalid value" 또는 "invalid type"이면, throw "DataError" DOMException을 발생시킨다.

  12. primaryKeyr로 설정한다.

  13. key보다 작고 this포지션이고, this방향이 "next"이면, throw "DataError" DOMException을 발생시킨다.

  14. key보다 크고 this포지션이고, this방향이 "prev"이면, throw "DataError" DOMException을 발생시킨다.

  15. key같고 this포지션이며, primaryKey보다 작거나 같고 this오브젝트 스토어 포지션이고, this방향이 "next"이면, throw "DataError" DOMException을 발생시킨다.

  16. key같고 this포지션이며, primaryKey보다 크거나 같고 this오브젝트 스토어 포지션이고, this방향이 "prev"이면, throw "DataError" DOMException을 발생시킨다.

  17. thisgot value flag를 false로 설정한다.

  18. requestthisrequest로 설정한다.

  19. requestprocessed flag를 false로 설정한다.

  20. requestdone flag를 false로 설정한다.

  21. operation커서 반복하기 알고리즘으로, 현재 Realm record, this, key, primaryKey로 실행한다.

  22. 요청 비동기 실행하기this소스 핸들, operation, request로 실행한다.

참고: 새 커서 데이터가 로드되기 전에 이 메서드를 두 번 이상 호출하면(예: 같은 onsuccess 핸들러에서 continuePrimaryKey() 를 두 번 호출하면), 두 번째 호출 시 "InvalidStateError" DOMException 이 발생합니다. 이는 커서의 got value flag가 false로 설정되었기 때문입니다.

다음 메서드들은 읽기 전용 트랜잭션 내에서 호출될 경우 "ReadOnlyError" DOMException 을 발생시키며, 트랜잭션활성 상태가 아닐 때 호출하면 "TransactionInactiveError" DOMException 을 발생시킵니다.
request = cursor . update(value)

커서가 가리키는 레코드의 값을 새로운 값으로 갱신합니다.

실효 오브젝트 스토어인라인 키를 사용할 때 가 변경된다면, "DataError" DOMException 이 발생합니다.

성공 시 requestresult레코드가 됩니다.

request = cursor . delete()

커서가 가리키는 레코드를 삭제합니다.

성공 시 requestresultundefined가 됩니다.

update(value) 메서드 단계는 다음과 같습니다:

  1. transactionthis트랜잭션으로 설정한다.

  2. transaction상태활성이 아니면, throw "TransactionInactiveError" DOMException을 발생시킨다.

  3. transaction읽기 전용 트랜잭션이면, throw "ReadOnlyError" DOMException을 발생시킨다.

  4. this소스 또는 실효 오브젝트 스토어가 삭제된 경우, throw "InvalidStateError" DOMException을 발생시킨다.

  5. thisgot value flag가 false이면(커서가 반복 중이거나 끝까지 반복된 경우), throw "InvalidStateError" DOMException을 발생시킨다.

  6. thiskey only flag가 true면, throw "InvalidStateError" DOMException을 발생시킨다.

  7. targetRealm을 user-agent가 정의한 Realm으로 설정한다.

  8. clonetargetRealmtransaction 동안 value복제본으로 설정한다. 예외가 발생하면 다시 던진다.

    값의 복제본을 만드는 이유? 값은 저장 시 직렬화되므로, 여기서 복사본으로 취급하면 이 명세의 다른 알고리즘이 이를 ECMAScript 값으로 다룰 수 있게 합니다. 단, 구현체는 동작 차이가 관찰되지 않는다면 최적화할 수 있습니다.
  9. this실효 오브젝트 스토어인라인 키를 사용한다면,

    1. kpkclone키 경로값에서 키 경로로 키 추출하기의 결과로 얻는다. 예외가 발생하면 다시 던진다.

    2. kpk가 실패하거나, 유효하지 않거나, 같지 않으면 this실효 키와, throw "DataError" DOMException을 발생시킨다.

  10. operation오브젝트 스토어에 레코드 저장하기 알고리즘으로, this실효 오브젝트 스토어, clone, this실효 키, false로 실행한다.

  11. 요청 비동기 실행하기this, operation으로 실행한 결과(IDBRequest)를 반환한다.

참고: 오브젝트 스토어에 레코드 저장 결과는, 커서가 이동한 이후 레코드가 삭제되었다면 새 레코드가 생성된다는 점입니다.

delete() 메서드 단계는 다음과 같습니다:

  1. transactionthis트랜잭션으로 설정한다.

  2. transaction상태활성이 아니면, throw "TransactionInactiveError" DOMException을 발생시킨다.

  3. transaction읽기 전용 트랜잭션이면, throw "ReadOnlyError" DOMException을 발생시킨다.

  4. this소스 또는 실효 오브젝트 스토어가 삭제된 경우, throw "InvalidStateError" DOMException을 발생시킨다.

  5. thisgot value flag가 false이면(커서가 반복 중이거나 끝까지 반복된 경우), throw "InvalidStateError" DOMException을 발생시킨다.

  6. thiskey only flag가 true이면, throw "InvalidStateError" DOMException을 발생시킨다.

  7. operation오브젝트 스토어에서 레코드 삭제하기 알고리즘으로, this실효 오브젝트 스토어, this실효 키로 실행한다.

  8. 요청 비동기 실행하기this, operation으로 실행한 결과(IDBRequest)를 반환한다.

커서key only flag 가 false로 설정된 경우, IDBCursorWithValue 인터페이스도 구현합니다.

[Exposed=(Window,Worker)]
interface IDBCursorWithValue : IDBCursor {
  readonly attribute any value;
};
cursor . value

커서의 현재 을 반환합니다.

value getter 단계는 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

트랜잭션의 scope에 있는 오브젝트 스토어의 이름 목록을 반환합니다. 업그레이드 트랜잭션의 경우, 이는 데이터베이스 내 모든 오브젝트 스토어입니다.

transaction . mode

트랜잭션이 생성될 때의 모드를 반환합니다 ("readonly" 또는 "readwrite"), 업그레이드 트랜잭션의 경우에는 "versionchange"입니다.

transaction . durability

트랜잭션이 생성될 때의 내구성 힌트를 반환합니다 ("strict", "relaxed"), 또는 "default".

transaction . db

트랜잭션의 연결을 반환합니다.

transaction . error

트랜잭션이 중단된 경우, 원인을 제공하는 에러(DOMException)를 반환합니다.

objectStoreNames getter 단계는 다음과 같습니다:

  1. names리스트로, scope에 있는 오브젝트 스토어 이름들의 목록으로 설정한다.

  2. names정렬된 이름 목록 생성하기의 결과(DOMStringList)를 반환한다.

참고: 이 속성에서 반환되는 각 리스트의 내용은 변경되지 않지만, 업그레이드 트랜잭션 중에 이후 호출 시 오브젝트 스토어가 생성·삭제됨에 따라 다른 내용을 포함할 수 있습니다.

mode getter 단계는 this모드를 반환한다.

durability getter 단계는 this내구성 힌트를 반환한다.

🚧 durability 속성은 이번 판에서 새로 추가되었습니다. Chrome 82, Edge 82, Firefox 126, Safari 15에서 지원됩니다. 🚧

db getter 단계는 thisconnection에 연결된 데이터베이스를 반환합니다.

error getter 단계는 this에러를 반환하며, 없으면 null을 반환합니다.

참고:트랜잭션이 실패한 요청으로 인해 중단된 경우, 이는 요청에러와 동일합니다. 이 트랜잭션이 이벤트 핸들러에서 처리되지 않은 예외로 인해 중단된 경우, 에러는 "AbortError" DOMException입니다. 트랜잭션이 커밋 중 에러로 인해 중단된 경우, 실패 원인(예: QuotaExceededError, 또는 "ConstraintError" 또는 "UnknownError" DOMException)을 반영합니다.

transaction . objectStore(name)

트랜잭션scope에 있는 IDBObjectStore를 반환합니다.

transaction . abort()

트랜잭션을 중단합니다. 모든 대기 중인 요청은 "AbortError" DOMException으로 실패하며, 데이터베이스에 이루어진 모든 변경사항이 되돌려집니다.

transaction . commit()

트랜잭션을 커밋하려고 시도합니다. 모든 대기 중인 요청이 완료될 수 있도록 허용되지만, 새로운 요청은 허용되지 않습니다. 대기 중인 요청의 success 이벤트를 기다리지 않고 트랜잭션을 빠르게 종료하도록 강제할 때 사용할 수 있습니다.

대기 중인 요청이 실패(예: 제약 조건 오류 등)하면 트랜잭션이 중단됩니다. 성공한 요청의 success 이벤트는 계속 발생하지만, 이벤트 핸들러에서 예외를 던져도 트랜잭션은 중단되지 않습니다. 마찬가지로 실패한 요청의 error 이벤트는 계속 발생하지만, preventDefault()를 호출해도 트랜잭션 중단을 막을 수 없습니다.

objectStore(name) 메서드 단계는 다음과 같습니다:

  1. this상태종료됨이면, throw "InvalidStateError" DOMException을 발생시킨다.

  2. store오브젝트 스토어이름이 name인 것을 thisscope에서 찾는다. 없으면 throw "NotFoundError" DOMException을 발생시킨다.

  3. storethis에 연결된 오브젝트 스토어 핸들을 반환한다.

참고: 동일한 IDBTransaction 인스턴스에서 같은 이름으로 이 메서드를 호출하면 항상 동일한 IDBObjectStore 인스턴스를 반환합니다.

참고: 반환된 IDBObjectStore 인스턴스는 해당 IDBTransaction 전용입니다. 다른 IDBTransaction에서 호출하면 다른 IDBObjectStore 인스턴스가 반환됩니다.

abort() 메서드 단계는 다음과 같습니다:

  1. this상태커밋 중 또는 종료됨이면, throw "InvalidStateError" DOMException을 발생시킨다.

  2. 트랜잭션 중단하기 알고리즘을 this와 null로 실행한다.

commit() 메서드 단계는 다음과 같습니다:

  1. this상태활성이 아니면, throw "InvalidStateError" DOMException을 발생시킨다.

  2. 트랜잭션 커밋하기 알고리즘을 this로 실행한다.

🚧 commit() 메서드는 이번 판에서 새로 추가되었습니다. Chrome 76, Edge 79, Firefox 74, Safari 15에서 지원됩니다. 🚧

참고: 일반적으로 트랜잭션에서 commit()를 직접 호출할 필요는 없습니다. 모든 대기 중인 요청이 완료되고 새로운 요청이 더 이상 생성되지 않으면 트랜잭션이 자동으로 커밋됩니다. 이 호출은 대기 중인 요청에서 이벤트가 발생하기를 기다리지 않고 커밋 프로세스를 시작하고자 할 때 사용할 수 있습니다.

onabort 속성은 이벤트 핸들러 IDL 속성이며, 이벤트 핸들러 이벤트 타입abort입니다.

oncomplete 속성은 이벤트 핸들러 IDL 속성이며, 이벤트 핸들러 이벤트 타입complete입니다.

onerror 속성은 이벤트 핸들러 IDL 속성이며, 이벤트 핸들러 이벤트 타입error입니다.

참고: 트랜잭션이 성공적으로 완료되었는지 확인하려면, 특정 요청success 이벤트가 아니라 트랜잭션complete 이벤트를 감지하세요. success 이벤트가 발생한 후에도 트랜잭션이 실패할 수 있기 때문입니다.

5. 알고리즘

5.1. 데이터베이스 연결 열기

storageKey가 요청한 데이터베이스와 데이터베이스 name, 데이터베이스 version, request데이터베이스 연결을 열기 위한 단계는 다음과 같다:

  1. queuestorageKeyname에 대한 연결 큐로 설정한다.

  2. requestqueue에 추가한다.

  3. queue의 이전 모든 요청이 처리될 때까지 기다린다.

  4. dbstorageKey 내에서 name 이름의 데이터베이스로 설정하고, 없으면 null로 한다.

  5. version이 undefined이면, db가 null이면 version을 1로, 아니면 db버전으로 설정한다.

  6. db가 null이면, db새 데이터베이스로 생성한다. 이름name, 버전은 0, 오브젝트 스토어는 없음으로 한다. 실패하면 적절한 에러(예: QuotaExceededError, 또는 "UnknownError" DOMException)를 반환한다.

  7. db버전version보다 크면, 새로 생성된 "VersionError" DOMException 을 반환하고 이 단계를 중단한다.

  8. connectiondb에 대한 새로운 연결로 설정한다.

  9. connection버전version으로 설정한다.

  10. db버전version보다 작으면, 다음을 수행한다:

    1. openConnectionsdb에 연결된, connection을 제외한 모든 연결 집합으로 설정한다.

    2. openConnections의 각 entry에 대해, close pending flag가 true가 아니면, 데이터베이스 태스크를 큐에 추가하여, versionchange 이벤트를 발생시킨다. 이벤트 이름은 versionchange 이고, entrydb버전version을 함께 전달한다.

      참고: 이 이벤트를 발생시키면 openConnections의 다른 객체들 중 하나 이상이 닫힐 수 있으며, 그런 경우 해당 객체에는 versionchange 이벤트가 발생하지 않는다. 이는 아직 이벤트가 발생하지 않았더라도 마찬가지다.

    3. 모든 이벤트가 발생할 때까지 기다린다.

    4. openConnections연결 중 아직 닫히지 않은 것이 있다면, 데이터베이스 태스크를 큐에 추가하여 version change 이벤트를 발생시킨다. 이벤트 이름은 blocked 이고, requestdb버전version을 전달한다.

    5. openConnections에 있는 모든 연결닫힐 때까지 기다린다.

    6. 데이터베이스 업그레이드connection, version, request로 실행한다.

    7. connection닫힌 경우라면, 새로 생성된 "AbortError" DOMException 을 반환하고 이 단계를 중단한다.

    8. request에러가 설정되어 있다면, 데이터베이스 연결 닫기 단계를 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을 사용하여 생성된 모든 트랜잭션이 완료될 때까지 기다린다. 완료되면 connection닫힘 상태가 된다.

  4. forced flag가 true인 경우, 이벤트를 발생시킨다. 이벤트 이름은 close 이고, connection에서 발생시킨다.

    참고: close 이벤트는 연결이 비정상적으로 닫힐 때만 발생한다. 예를 들어 storage key의 저장소가 비워지거나, 손상 또는 I/O 오류가 발생한 경우이다. close() 가 명시적으로 호출된 경우에는 이벤트가 발생하지 않는다.

참고: connectionclose pending flag가 true로 설정된 후에는, 해당 connection을 통해 새 트랜잭션을 생성할 수 없다. 트랜잭션을 생성하는 모든 메서드는 먼저 connectionclose pending flag를 확인하고 true이면 예외를 발생시킨다.

참고: connection이 닫히면, 데이터베이스 업그레이드를 위한 단계와 데이터베이스 삭제 단계를 둘 다 대기시킬 수 있으며, database에 대한 connection들이 닫히기 전까지 진행하지 않는다.

5. 데이터베이스 삭제

storageKey가 삭제를 요청한 데이터베이스와 데이터베이스 name, request데이터베이스 삭제 단계는 다음과 같다:

  1. queuestorageKeyname에 대한 연결 큐로 설정한다.

  2. requestqueue에 추가한다.

  3. queue에 있는 모든 이전 요청이 처리될 때까지 기다린다.

  4. dbstorageKey 내에서 name 이름의 데이터베이스로 설정한다. 존재하지 않으면 0(영)을 반환한다.

  5. openConnectionsdb에 연결된 모든 연결 집합으로 설정한다.

  6. openConnections의 각 entry에 대해, close pending flag가 true가 아니면, 데이터베이스 태스크 큐에 추가하여 versionchange 이벤트 발생시킨다. 이벤트 이름은 versionchange이고, entrydb버전과 null을 전달한다.

    참고: 이 이벤트를 발생시키면 openConnections의 다른 객체들 중 하나 이상이 닫힐 수 있으며, 그런 경우 해당 객체에는 versionchange 이벤트가 발생하지 않는다. 이는 아직 이벤트가 발생하지 않았더라도 마찬가지다.

  7. 모든 이벤트가 발생할 때까지 기다린다.

  8. openConnections연결 중 아직 닫히지 않은 것이 있다면, 데이터베이스 태스크 큐에 추가하여 versionchange 이벤트 발생시킨다. 이벤트 이름은 blocked 이고, requestdb버전과 null을 전달한다.

  9. openConnections에 있는 모든 연결닫힐 때까지 기다린다.

  10. versiondb버전으로 설정한다.

  11. db를 삭제한다. 실패하면 적절한 에러(예: QuotaExceededError, 또는 "UnknownError" DOMException)를 반환한다.

  12. version을 반환한다.

5.4. 트랜잭션 커밋

transaction을 커밋하기 위한 트랜잭션 커밋 단계는 다음과 같다:

  1. transactionstate커밋 중으로 설정한다.

  2. 다음 단계를 병렬로 실행한다:

    1. transactionrequest list의 모든 항목이 처리됨 상태가 될 때까지 기다린다.

    2. transactionstate가 더 이상 커밋 중이 아니면, 이 단계를 종료한다.

    3. transaction에 의해 이루어진 모든 미처리 변경사항을 데이터베이스에 기록하려 시도한다. 이 때 transaction내구성 힌트를 고려한다.

    4. 변경사항을 데이터베이스에 기록하는 동안 에러가 발생하면, 트랜잭션 중단하기 단계를 transaction과 에러에 적합한 타입(예: QuotaExceededError 또는 "UnknownError" DOMException)로 실행하고, 이 단계를 종료한다.

    5. 데이터베이스 태스크 큐에 추가하여 다음 단계를 실행한다:

      1. transaction업그레이드 트랜잭션이면, transactionconnection에 연결된 데이터베이스업그레이드 트랜잭션을 null로 설정한다.

      2. transactionstate종료됨으로 설정한다.

      3. 이벤트를 발생시킨다. 이벤트 이름은 complete 이고, transaction에서 발생시킨다.

        참고: 이 이벤트 핸들러 중 하나에서 예외가 발생해도 트랜잭션은 이미 커밋된다. 데이터베이스 변경사항이 먼저 기록된 후에 이벤트가 발생하기 때문이다. 트랜잭션이 성공적으로 기록된 이후에 complete 이벤트가 발생한다.

      4. transaction업그레이드 트랜잭션이면, transaction에 연결된 requestrequest로 설정하고, requesttransaction을 null로 설정한다.

5.5. 트랜잭션 중단

transaction을 중단할 때, error와 함께 트랜잭션 중단 단계는 다음과 같다:

  1. transaction상태종료됨이면, 이 단계를 중단한다.

  2. transactiondatabase에 가한 모든 변경사항을 되돌린다. 업그레이드 트랜잭션의 경우, 오브젝트 스토어 집합과 인덱스의 변경, 버전 변경도 포함된다. 트랜잭션 중에 생성된 모든 오브젝트 스토어인덱스는 이제 다른 알고리즘에서는 삭제된 것으로 간주된다.

  3. transaction업그레이드 트랜잭션이면, 업그레이드 트랜잭션 중단 단계를 transaction으로 실행한다.

    참고: 이는 transaction에 연결된 모든 connection, 오브젝트 스토어 핸들, 인덱스 핸들 인스턴스의 변경사항도 되돌린다.

  4. transaction상태종료됨으로 설정한다.

  5. transaction에러error로 설정한다.

  6. transaction의 request list의 각 request에 대해, 비동기 요청 실행 단계를 중단하고, requestprocessed flag를 true로 설정하며, 데이터베이스 태스크 큐에 추가하여 다음 단계를 실행한다:

    1. requestdone flag를 true로 설정한다.

    2. requestresult를 undefined로 설정한다.

    3. request에러를 새로 생성된 "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: transaction상태활성임을 확인한다.

  3. request가 주어지지 않았으면, sourcesource로 하는 새 request를 생성한다.

  4. requesttransactionrequest list 끝에 추가한다.

  5. 다음 단계를 병렬로 실행한다:

    1. requesttransactionrequest listprocessed가 아닌 첫 번째 항목이 될 때까지 기다린다.

    2. resultoperation을 수행한 결과로 설정한다.

    3. result가 에러이고 transaction상태커밋 중이면, 트랜잭션 중단 단계를 transactionresult로 실행하고, 이 단계를 종료한다.

    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. 데이터베이스 업그레이드

connection(connection)과 새로운 version, request데이터베이스 업그레이드 단계를 실행하려면 다음을 따른다:

  1. dbconnection데이터베이스로 설정한다.

  2. transactionconnectionconnection으로 사용하는 새로운 업그레이드 트랜잭션으로 생성한다.

  3. transactionscopeconnectionobject store set으로 설정한다.

  4. db업그레이드 트랜잭션transaction으로 설정한다.

  5. transaction상태비활성으로 설정한다.

  6. transaction을 시작한다.

    참고:트랜잭션이 종료될 때까지, 같은 데이터베이스에 대해 다른 connection을 열 수 없다.

  7. old versiondb버전으로 설정한다.

  8. db버전version으로 설정한다. 이 변경은 트랜잭션의 일부로 간주되며, 트랜잭션이 중단되면 변경이 되돌려진다.

  9. requestprocessed flag를 true로 설정한다.

  10. 데이터베이스 태스크 큐에 추가하여 다음 단계를 실행한다:

    1. requestresultconnection으로 설정한다.

    2. requesttransactiontransaction으로 설정한다.

    3. requestdone flag를 true로 설정한다.

    4. transaction상태활성으로 설정한다.

    5. didThrowversionchange 이벤트 발생 결과로 설정한다. 이벤트 이름은 upgradeneeded이고, request에서 old versionversion을 전달한다.

    6. transaction상태활성이면:

      1. transaction상태비활성으로 설정한다.

      2. didThrow가 true이면, 트랜잭션 중단 단계를 transaction과 새로 생성된 "AbortError" DOMException으로 실행한다.

  11. transaction종료될 때까지 기다린다.

    참고: 트랜잭션수명 동안 호출되는 일부 알고리즘(예: 트랜잭션 커밋 단계, 트랜잭션 중단 단계 등)은 업그레이드 트랜잭션에 특화된 단계를 포함한다.

5.8. 업그레이드 트랜잭션 중단

transaction으로 업그레이드 트랜잭션 중단 단계는 다음과 같다:

참고: 이 단계는 트랜잭션 중단 단계에 의해 필요할 때마다 실행되며, 데이터베이스의 변경사항(예: 연결된 오브젝트 스토어인덱스 집합, 버전 변경 등)을 되돌린다.

  1. connectiontransactionconnection으로 설정한다.

  2. databaseconnectiondatabase로 설정한다.

  3. connectionversiondatabase가 기존에 존재했으면 databaseversion으로, 새로 생성된 경우 0(영)으로 설정한다.

    참고: 이는 version 속성 값을 IDBDatabase 객체에서 반환되는 값으로 되돌린다.

  4. connectionobject store setdatabase가 기존에 존재했으면 database오브젝트 스토어 집합으로, 새로 생성된 경우 빈 집합으로 설정한다.

    참고: 이는 objectStoreNames 속성 값을 IDBDatabase 객체에서 반환되는 값으로 되돌린다.

  5. transaction에 연관된 각 오브젝트 스토어 핸들 handle에 대해(트랜잭션 중에 생성되거나 삭제된 오브젝트 스토어에 대한 핸들도 포함):

    1. handleobject store가 트랜잭션 중 새로 생성된 것이 아니면, handlenameobject storename으로 설정한다.

    2. handleindex set을 해당 object store를 참조하는 인덱스 집합으로 설정한다.

    참고: 이는 연관된 nameindexNames 속성 값을 IDBObjectStore 객체에서 반환되는 값으로 되돌린다.

    어떻게 관찰 가능한가? 스크립트는 트랜잭션이 중단된 후 IDBTransaction 인스턴스에서 objectStore() 메서드를 통해 오브젝트 스토어에 접근할 수는 없지만, IDBObjectStore 인스턴스에 대한 참조는 가질 수 있으며, 이때 nameindexNames 속성을 쿼리할 수 있다.
  6. transaction에 연관된 각 인덱스 핸들 handle에 대해(트랜잭션 중에 생성되거나 삭제된 인덱스에 대한 핸들도 포함):

    1. handleindex가 트랜잭션 중 새로 생성된 것이 아니면, handlenameindexname으로 설정한다.

    참고: 이는 연관된 name 속성 값을 IDBIndex 객체에서 반환되는 값으로 되돌린다.

    어떻게 관찰 가능한가? 스크립트는 트랜잭션이 중단된 후 IDBObjectStore 인스턴스에서 index() 메서드를 통해 인덱스에 접근할 수는 없지만, IDBIndex 인스턴스에 대한 참조는 가질 수 있으며, 이때 name 속성을 쿼리할 수 있다.

참고: name 속성은 IDBDatabase 인스턴스에서 수정되지 않는다. 업그레이드 트랜잭션을 중단할 때 새로운 데이터베이스를 생성 중이어도 마찬가지이다.

5.9. 성공 이벤트 발생

request에서 성공 이벤트 발생 단계는 다음과 같다:

  1. eventEvent를 사용해 이벤트 생성 결과로 설정한다.

  2. eventtype 속성을 "success"로 설정한다.

  3. eventbubblescancelable 속성을 false로 설정한다.

  4. transactionrequest트랜잭션으로 설정한다.

  5. legacyOutputDidListenersThrowFlag를 초기값 false로 설정한다.

  6. transaction상태비활성이면, transaction상태활성으로 설정한다.

  7. 이벤트 디스패치request에서 eventlegacyOutputDidListenersThrowFlag로 실행한다.

  8. transaction상태활성이면:

    1. transaction상태비활성으로 설정한다.

    2. legacyOutputDidListenersThrowFlag가 true이면, 트랜잭션 중단 단계에 따라 transaction과 새로 생성된 "AbortError" DOMException으로 실행한다.

    3. transactionrequest list가 비어 있으면, 트랜잭션 커밋 단계를 transaction으로 실행한다.

5.10. 에러 이벤트 발생

request에서 에러 이벤트 발생 단계는 다음과 같다:

  1. eventEvent를 사용해 이벤트 생성 결과로 설정한다.

  2. eventtype 속성을 "error"로 설정한다.

  3. eventbubblescancelable 속성을 true로 설정한다.

  4. transactionrequest트랜잭션으로 설정한다.

  5. legacyOutputDidListenersThrowFlag를 초기값 false로 설정한다.

  6. transaction상태비활성이면, transaction상태활성으로 설정한다.

  7. 이벤트 디스패치request에서 eventlegacyOutputDidListenersThrowFlag로 실행한다.

  8. transaction상태활성이면:

    1. transaction상태비활성으로 설정한다.

    2. legacyOutputDidListenersThrowFlag가 true이면, 트랜잭션 중단 단계에 따라 transaction과 새로 생성된 "AbortError" DOMException으로 실행하고, 이 단계를 종료한다. 이는 eventcanceled flag가 false여도 실행된다.

      참고: 에러 이벤트가 발생하고 이벤트 핸들러 중 하나에서 예외가 발생하면, transactionerror 속성은 requesterror 대신 AbortError로 설정된다. preventDefault() 가 호출되지 않아도 마찬가지이다.

    3. eventcanceled flag가 false이면, 트랜잭션 중단 단계를 transactionrequesterror로 실행하고, 이 단계를 종료한다.

    4. transactionrequest list가 비어 있으면, 트랜잭션 커밋 단계를 transaction으로 실행한다.

5.11. 값 복제하기

valuetargetRealm 내에서 transaction 중에 복제하려면 다음 단계를 따른다:

  1. Assert: transaction상태활성임을 확인한다.

  2. transaction상태비활성으로 설정한다.

    참고: 트랜잭션비활성으로 만드는 것은, 복제 작업 중에 getter나 기타 부수 효과가 트랜잭션에 추가 요청을 하지 못하도록 하기 위함이다.

  3. serialized? StructuredSerializeForStorage(value)의 결과로 설정한다.

  4. clone? StructuredDeserialize(serialized, targetRealm)의 결과로 설정한다.

  5. transaction상태활성으로 설정한다.

  6. clone을 반환한다.

5.12. 여러 항목을 가져오기 위한 요청 생성

targetRealm, sourceHandle, kind, queryOrOptions, 선택적 count오브젝트 스토어 또는 인덱스에서 여러 항목을 가져오는 요청 생성 단계는 다음과 같다:

  1. sourcesourceHandle에서 가져온 인덱스 또는 오브젝트 스토어로 설정한다. sourceHandle인덱스 핸들이면, source연결된 인덱스이고, 아니면 source연결된 오브젝트 스토어이다.

  2. source가 삭제된 경우, throw "InvalidStateError" DOMException을 발생시킨다.

  3. source인덱스이고, source오브젝트 스토어가 삭제된 경우, throw "InvalidStateError" DOMException을 발생시킨다.

  4. transactionsourceHandle트랜잭션으로 설정한다.

  5. transaction상태활성이 아니면, throw "TransactionInactiveError" DOMException을 발생시킨다.

  6. range키 범위로 설정한다.

  7. 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. source인덱스면, operationretrieve multiple items from an index (targetRealm, source, range, kind, direction, count 있으면 포함)으로 설정한다.

  12. 그 외의 경우 operationretrieve multiple items from an object store (targetRealm, source, range, kind, direction, count 있으면 포함)으로 설정한다.

  13. 비동기적으로 요청 실행sourceHandleoperation으로 실행한 결과(IDBRequest)를 반환한다.

참고: range 또는 키 범위 (IDBKeyRange)일 수 있으며, 가져올 레코드 항목을 지정한다. null 또는 주어지지 않은 경우 제한 없는 키 범위가 사용된다. count가 지정되어 있고 범위 내에 count보다 많은 레코드가 있으면, 처음 count개만 가져온다.

6. 데이터베이스 연산

이 섹션에서는 오브젝트 스토어인덱스에서 데이터베이스의 데이터를 대상으로 수행되는 다양한 연산을 설명한다. 이러한 연산은 비동기적으로 요청 실행 단계에 의해 실행된다.

참고: 아래 연산 단계에서 StructuredDeserialize() 호출은 오류를 발생시키지 않는다고 단언할 수 있다( ! 접두사로 표시됨). 이는 오직 StructuredSerializeForStorage()의 이전 출력값만을 대상으로 동작하기 때문이다.

6.1. 오브젝트 스토어 저장 연산

store, value, 선택적 key, no-overwrite flag레코드를 오브젝트 스토어에 저장하려면 다음 단계를 따른다:

  1. store키 생성기를 사용하는 경우:

    1. key가 undefined인 경우:

      1. key키 생성(store)의 결과로 설정한다.

      2. key가 실패인 경우, 이 연산은 "ConstraintError" DOMException으로 실패한다. 추가 단계 없이 이 알고리즘을 중단한다.

      3. store인라인 키도 사용하는 경우, 키 경로를 이용해 값에 키 주입 단계를 value, key, store키 경로로 실행한다.

    2. 그 외의 경우, 키 생성기 업데이트 가능 단계를 storekey로 실행한다.

  2. no-overwrite flag가 true로 지정된 경우, storekey같은 키를 가진 레코드가 이미 존재하면, 이 연산은 "ConstraintError" DOMException으로 실패한다. 추가 단계 없이 이 알고리즘을 중단한다.

  3. storekey같은 키를 가진 레코드가 이미 존재하면, 오브젝트 스토어에서 레코드 삭제 단계를 통해 store에서 해당 레코드를 제거한다.

  4. storekey를 키로 하고, ! StructuredSerializeForStorage(value) 를 값으로 하는 레코드를 저장한다. 레코드는 오브젝트 스토어의 레코드 목록에 저장되며, 목록은 레코드의 키가 오름차순으로 정렬된다.

  5. store참조하는 각 index에 대해:

    1. index key키 경로를 이용해 값에서 키 추출 단계(value, index키 경로, indexmultiEntry 플래그)의 결과로 설정한다.

    2. index key가 예외이거나, 유효하지 않거나, 실패이면, 해당 index에 대해 추가 동작 없이 다음 인덱스로 진행한다.

      참고: 이 단계에서 발생한 예외는 다시 던지지 않는다.

    3. indexmultiEntry 플래그가 false이거나, index key배열 키가 아니고, index같은 index key레코드가 이미 존재하며, indexunique 플래그가 true이면, 이 연산은 "ConstraintError" DOMException으로 실패한다. 추가 단계 없이 이 알고리즘을 중단한다.

    4. indexmultiEntry 플래그가 true이고, index key배열 키이며, index같은 subkeys 중 하나인 레코드가 이미 존재하며, indexunique 플래그가 true이면, 이 연산은 "ConstraintError" DOMException으로 실패한다. 추가 단계 없이 이 알고리즘을 중단한다.

    5. indexmultiEntry 플래그가 false이거나, index key배열 키가 아니라면, indexindex key를 키로 하고 key를 값으로 하는 레코드를 저장한다. 해당 레코드는 index레코드 목록에 저장되며, 목록은 키를 기준으로 우선 정렬하고, 값을 기준으로 2차 정렬하며, 모두 오름차순으로 정렬된다.

    6. indexmultiEntry 플래그가 true이고, index key배열 키라면, subkeys의 각 subkey에 대해, indexsubkey를 키로 key를 값으로 하는 레코드를 저장한다. 해당 레코드는 index레코드 목록에 저장되며, 목록은 키 기준 우선, 값 기준 2차로 오름차순 정렬된다.

      참고: subkeys가 없는 경우도 유효하며, 이 경우 인덱스에 아무 레코드도 추가되지 않는다.

      참고: subkeys의 멤버가 배열 키여도, 해당 멤버 자체를 인덱스 레코드의 키로 바로 사용한다. 중첩된 배열 키는 펼치거나 여러 행으로 분해하지 않는다. 오직 가장 바깥 배열 키만 사용된다.

  6. key를 반환한다.

6.2. 오브젝트 스토어 조회 연산

targetRealm, store, range오브젝트 스토어에서 값 조회하려면 다음 단계를 실행한다. 반환값은 undefined, ECMAScript 값, 또는 에러(DOMException)이다:

  1. recordstore레코드 목록range에 포함되는 첫 번째 레코드로 설정한다. 없다면 아무것도 선택하지 않는다.

  2. record가 없으면 undefined를 반환한다.

  3. serializedrecord으로 설정한다. 만약 내부 저장소에서 값을 읽는 중 에러가 발생하면, 새로 생성된 "NotReadableError" DOMException을 반환한다.

  4. ! StructuredDeserialize(serialized, targetRealm)의 결과를 반환한다.

store, range오브젝트 스토어에서 키 조회하려면 다음 단계를 실행한다:

  1. recordstore레코드 목록range에 포함되는 첫 번째 레코드로 설정한다. 없다면 아무것도 선택하지 않는다.

  2. record가 없으면 undefined를 반환한다.

  3. 키를 값으로 변환(record의 키) 결과를 반환한다.

targetRealm, store, range, kind, direction, 선택적 count오브젝트 스토어에서 여러 항목 조회하려면 다음 단계를 실행한다:

  1. count가 주어지지 않았거나 0(영)이면, count를 무한대로 설정한다.

  2. records를 빈 목록으로 설정한다.

  3. direction이 "next" 또는 "nextunique"인 경우, store레코드 목록range에 포함되는 처음 count개의 레코드를 records로 설정한다.

  4. direction이 "prev" 또는 "prevunique"인 경우, store레코드 목록range에 포함되는 마지막 count개를 records로 설정한다.

  5. list를 빈 목록으로 설정한다.

  6. records의 각 record에 대해 kind에 따라 분기한다:

    "key"
    1. key키를 값으로 변환(record의 키) 결과로 설정한다.

    2. listkey를 추가한다.

    "value"
    1. serializedrecord으로 설정한다.

    2. value! StructuredDeserialize(serialized, targetRealm) 결과로 설정한다.

    3. listvalue를 추가한다.

    "record"
    1. keyrecord의 키로 설정한다.

    2. serializedrecord으로 설정한다.

    3. value! StructuredDeserialize(serialized, targetRealm) 결과로 설정한다.

    4. recordSnapshot레코드 스냅샷으로 새로 생성하고 keykey, valuevalue, primary keykey를 설정한다.

    5. listrecordSnapshot을 추가한다.

  7. list를 반환한다.

6.3. 인덱스 검색 작업

targetRealm, index, range인덱스에서 참조된 값 검색하기 단계:

  1. recordindex레코드 목록(list of records)range포함되는(in) 키(key)를 가진 첫 번째 레코드(record)로 설정한다.

  2. record가 없으면 undefined를 반환한다.

  3. serializedrecord참조 값(referenced value)으로 설정한다.

  4. ! StructuredDeserialize(serialized, targetRealm)를 반환한다.

index, range인덱스에서 값 검색하기 단계:

  1. recordindex레코드 목록(list of records)range포함되는(in) 키(key)를 가진 첫 번째 레코드(record)로 설정한다.

  2. record가 없으면 undefined를 반환한다.

  3. record값(value)으로 키를 값으로 변환하기의 결과를 반환한다.

targetRealm, index, range, kind, direction, 선택적 count인덱스에서 여러 항목 검색하기 단계:

  1. count가 주어지지 않았거나 0이면, count를 infinity로 설정한다.

  2. records를 빈 목록(list)으로 설정한다. 레코드(records) 타입이다.

  3. direction에 따라:

    "next"
    1. recordsindex레코드 목록(list of records)range포함되는(in) 키(key)를 가진 첫 count개로 설정한다.

    "nextunique"
    1. rangeRecordsindex레코드 목록(list of records)range포함되는(in) 키(key)를 가진 레코드들의 목록으로 설정한다.

    2. rangeRecordsLengthrangeRecords크기(size)로 설정한다.

    3. i를 0으로 설정한다.

    4. irangeRecordsLength보다 작을 동안:

      1. i를 1 증가시킨다.

      2. record크기(size)count와 같으면 break한다.

      3. 키 비교(compare two keys)의 결과가 |rangeRecords[i]|와 |rangeRecords[i-1]|의 키를 비교해 같으면 continue한다.

      4. 그 외에는 append |rangeRecords[i]|를 records에 추가한다.

    "prev"
    1. recordsindex레코드 목록(list of records)range포함되는(in) 키(key)를 가진 마지막 count개로 설정한다.

    "prevunique"
    1. rangeRecordsindex레코드 목록(list of records)range포함되는(in) 키(key)를 가진 레코드들의 목록으로 설정한다.

    2. rangeRecordsLengthrangeRecords크기(size)로 설정한다.

    3. i를 0으로 설정한다.

    4. irangeRecordsLength보다 작을 동안:

      1. i를 1 증가시킨다.

      2. record크기(size)count와 같으면 break한다.

      3. 키 비교(compare two keys)의 결과가 |rangeRecords[i]|와 |rangeRecords[i-1]|의 키를 비교해 같으면 continue한다.

      4. 그 외에는 prepend |rangeRecords[i]|를 records에 추가한다.

  4. list를 빈 목록(list)으로 설정한다.

  5. recordsrecord에 대해, kind에 따라:

    "key"
    1. keyrecord의 값으로 키를 값으로 변환하기의 결과로 설정한다.

    2. listkey를 추가한다.

    "value"
    1. serializedrecord참조 값(referenced value)으로 설정한다.

    2. value! StructuredDeserialize(serialized, targetRealm)의 결과로 설정한다.

    3. listvalue를 추가한다.

    "record"
    1. index keyrecord의 키로 설정한다.

    2. keyrecord의 값으로 설정한다.

    3. serializedrecord참조 값(referenced value)으로 설정한다.

    4. value! StructuredDeserialize(serialized, targetRealm)의 결과로 설정한다.

    5. recordSnapshotindex key를 key로, value를 value로, key를 primary key로 하는 새로운 레코드 스냅샷(record snapshot)으로 설정한다.

    6. listrecordSnapshot을 추가한다.

  6. list를 반환한다.

6.4. 오브젝트 스토어 삭제 작업

store, range오브젝트 스토어에서 레코드 삭제하기 단계:

  1. store레코드 목록(list of records)에서 range포함되는(in) 키를 가진 모든 레코드를 제거한다.

  2. store참조하는 각 index에 대해, index레코드 목록(list of records)에서 값이 range포함되는(in) 모든 레코드(record)를 제거한다(해당 레코드가 존재하는 경우).

  3. undefined를 반환한다.

6.5. 레코드 개수 세기 작업

source, range범위 내 레코드 개수 세기 단계:

  1. countsource의 레코드 중 range포함되는(in) 키를 가진 레코드 개수로 설정한다.

  2. count를 반환한다.

6.6. 오브젝트 스토어 비우기 작업

store오브젝트 스토어 비우기 단계:

  1. store에서 모든 레코드를 제거한다.

  2. store참조하는 모든 인덱스(index)에서 모든 레코드(record)를 제거한다.

  3. undefined를 반환한다.

6.7. 커서 반복 작업

targetRealm, cursor, 선택적 key, primaryKey (반복할 위치), 선택적 count커서 반복하기 단계:

  1. sourcecursorsource로 설정한다.

  2. directioncursordirection으로 설정한다.

  3. Assert: primaryKey가 주어지면, source인덱스(index)이고, direction은 "next" 또는 "prev"여야 한다.

  4. recordssource레코드 목록으로 설정한다.

    NOTE: records는 항상 오름차순 순서로 정렬되어 있다. source인덱스(index)인 경우, records오름차순 값(value) 순서로 2차 정렬된다 (여기서 인덱스의 값은 참조된 오브젝트 스토어의 레코드임).

  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이 있고 source오브젝트 스토어라면:

        • 레코드의 키가 커야 position보다.

      • position이 있고 source인덱스라면:

        • 레코드의 키가 같고, 레코드의 값이 커야 object store position보다.

        • 레코드의 키가 커야 position보다.

      • 레코드의 키가 range에 포함되어야 한다.

      "nextunique"

      found recordrecords 중 다음 조건을 모두 만족하는 첫 번째 레코드로 설정한다:

      • key가 주어졌다면:

      • position이 주어졌다면:

        • 레코드의 키가 커야 position보다.

      • 레코드의 키가 range에 포함되어야 한다.

      "prev"

      found recordrecords 중 다음 조건을 모두 만족하는 마지막 레코드로 설정한다:

      "prevunique"

      temp recordrecords 중 다음 조건을 모두 만족하는 마지막 레코드로 설정한다:

      • key가 주어졌다면:

      • position이 주어졌다면:

        • 레코드의 키가 작아야 position보다.

      • 레코드의 키가 range에 포함되어야 한다.

      temp record가 있으면, found recordrecordskey같은 첫 번째 레코드로 설정한다.

      NOTE: "prevunique" 반복은 "nextunique" 반복과 동일한 레코드를 역순으로 방문한다.

    2. found record가 없으면 다음을 실행한다:

      1. cursorkey를 undefined로 설정한다.

      2. source인덱스라면, cursorobject store position을 undefined로 설정한다.

      3. cursorkey only flag가 false라면, cursorvalue를 undefined로 설정한다.

      4. null을 반환한다.

    3. positionfound record의 키로 설정한다.

    4. source인덱스라면, object store positionfound record의 값으로 설정한다.

    5. count를 1 감소시킨다.

  10. cursorpositionposition으로 설정한다.

  11. source인덱스라면, cursorobject store positionobject store position으로 설정한다.

  12. cursorkeyfound record의 키로 설정한다.

  13. cursorkey only flag가 false라면:

    1. serializedsource오브젝트 스토어일 때 found recordvalue로, 그 외에는 found recordreferenced value로 설정한다.

    2. cursorvalue! StructuredDeserialize(serialized, targetRealm)로 설정한다.

  14. cursorgot value flag를 true로 설정한다.

  15. cursor를 반환한다.

7. ECMAScript 바인딩

이 섹션은 본 명세에서 정의된 값을 ECMAScript 값으로 변환하는 방법과 그 반대, 그리고 키 경로(key path)를 사용해 ECMAScript 값에서 추출하거나 주입하는 방법을 정의합니다. 이 섹션은 타입, 알고리즘, 그리고 ECMAScript 언어 명세의 일부 알고리즘 규칙을 참조합니다. [ECMA-262] 여기서 자세히 설명되지 않은 변환은 [WEBIDL]에서 정의됩니다.

7.1. 값에서 키 추출하기

value, keyPath, 선택적 multiEntry flag키 경로로 값에서 키 추출하기 단계. 이 단계의 결과는 , invalid, failure, 또는 예외 발생일 수 있습니다.

  1. rvalue, keyPath키 경로 평가(evaluating a key path on a value)의 결과로 설정합니다. 예외가 발생하면 다시 던집니다.

  2. r이 failure면, failure를 반환합니다.

  3. multiEntry flag가 false면 keyr값을 키로 변환하기의 결과로, 그렇지 않으면 r값을 multiEntry 키로 변환하기의 결과로 설정합니다. 예외 발생 시 다시 던집니다.

  4. key가 "invalid value" 또는 "invalid type"이면 invalid를 반환합니다.

  5. key를 반환합니다.

value, keyPath키 경로로 값 평가하기 단계. 이 단계의 결과는 ECMAScript 값 또는 failure, 또는 예외 발생일 수 있습니다.

  1. keyPath가 문자열 리스트라면:

    1. resultArray 객체(코드 []와 같이 생성)로 새로 만듭니다.

    2. i를 0으로 설정합니다.

    3. item에 대해 keyPath를 순회합니다:

      1. keyitem, value로 재귀적으로 키 경로로 값 평가하기의 결과로 설정합니다.

      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를 반환합니다.

      NOTE: 키 경로 시퀀스는 중첩될 수 없으므로, 이 알고리즘은 재귀가 한 단계만 발생합니다.

  2. keyPath가 빈 문자열이면 value를 반환하고 남은 단계는 건너뜁니다.

  3. identifierskeyPath를 U+002E FULL STOP 문자(.)로 strictly splitting하여 얻은 결과로 설정합니다.

  4. identifier에 대해 identifiers를 순회하며, 아래 단계로 이동합니다:

    만약 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를 반환합니다.

NOTE: 위 단계에서 Assertion이 가능한 이유는 이 알고리즘이 StructuredDeserialize의 출력값만 다루고 오직 "own" 속성만 접근하기 때문입니다.

7.2. 키를 값에 주입하기

NOTE: 이 섹션에서 사용하는 키 경로는 항상 문자열이며, 시퀀스가 아닙니다. 키 생성기를 사용하면서 키 경로가 시퀀스인 오브젝트 스토어를 만들 수 없기 때문입니다.

valuekeyPath키를 값에 주입할 수 있는지 확인하기 단계. 결과는 true 또는 false입니다.

  1. identifierskeyPath를 U+002E FULL STOP 문자(.)로 strictly splitting한 결과로 설정합니다.

  2. Assert: identifiers는 빈 값이 아닙니다.

  3. identifiers의 마지막 항목을 제거합니다.

  4. 남은 identifiers 각각에 대해(순회),

    1. valueObject 또는 Array가 아니면 false를 반환합니다.

    2. hop! HasOwnProperty(value, identifier)의 결과로 설정합니다.

    3. hop이 false면 true를 반환합니다.

    4. value! Get(value, identifier)로 설정합니다.

  5. valueObject 또는 Array이면 true, 아니면 false를 반환합니다.

NOTE: 위 단계에서 Assertion이 가능한 이유는 이 알고리즘이 StructuredDeserialize의 출력값만 다루기 때문입니다.

value, key, keyPath키 경로로 값에 키 주입하기 단계:

  1. identifierskeyPath를 U+002E FULL STOP 문자(.)로 strictly splitting한 결과로 설정합니다.

  2. Assert: identifiers는 빈 값이 아닙니다.

  3. lastidentifiers의 마지막 항목으로 설정하고, 리스트에서 제거합니다.

  4. 남은 identifiers 각각에 대해(순회):

    1. Assert: valueObject 또는 Array입니다.

    2. hop! HasOwnProperty(value, identifier)의 결과로 설정합니다.

    3. hop이 false이면:

      1. oObject({})로 새로 생성합니다.

      2. statusCreateDataProperty(value, identifier, o)의 결과로 설정합니다.

      3. Assert: status는 true입니다.

    4. value! Get(value, identifier)로 설정합니다.

  5. Assert: valueObject 또는 Array입니다.

  6. keyValuekey키를 값으로 변환하기의 결과로 설정합니다.

  7. statusCreateDataProperty(value, last, keyValue)의 결과로 설정합니다.

  8. Assert: status는 true입니다.

NOTE: 위 단계에서 Assertion이 가능한 이유는 이 알고리즘이 StructuredDeserialize의 출력값만 다루며, 키를 값에 주입할 수 있는지 확인하기 단계를 이미 실행했기 때문입니다.

7.3. 키를 값으로 변환하기

key키를 값으로 변환하기 단계. 결과는 ECMAScript 값입니다.

  1. typekey타입(type)으로 설정합니다.

  2. valuekey값(value)으로 설정합니다.

  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길이(length)로 설정합니다.

    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크기(size)로 설정합니다.

    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과 선택적 set seen으로 값을 키로 변환하기 단계. 결과는 , "invalid value", "invalid type" 또는 예외 발생일 수 있습니다.

  1. seen이 없으면, seen을 새로운 빈 set으로 설정합니다.

  2. seen포함하는 input이 있으면 "invalid value"를 반환합니다.

  3. 아래에 해당하는 단계로 이동합니다:

    만약 Type(input)이 Number라면
    1. input이 NaN이면 "invalid value"를 반환합니다.

    2. 그 외에는 를 새로 만들어 typenumber, valueinput으로 반환합니다.

    inputDate이고([[DateValue]] 내부 슬롯이 있으면)
    1. msinput의 [[DateValue]] 내부 슬롯 값으로 설정합니다.

    2. ms가 NaN이면 "invalid value"를 반환합니다.

    3. 그 외에는 를 새로 만들어 typedate, valuems로 반환합니다.

    Type(input)이 String이라면
    1. 를 새로 만들어 typestring, valueinput으로 반환합니다.

    inputbuffer source type이면
    1. inputdetached이면 "invalid value"를 반환합니다.

    2. bytes버퍼 소스가 가진 바이트를 복사(input)의 결과로 설정합니다.

    3. 를 새로 만들어 typebinary, valuebytes로 반환합니다.

    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. Append keykeys에 추가합니다.

      8. index를 1 증가시킵니다.

    6. array key를 새로 만들어 valuekeys로 반환합니다.

    그 외의 경우

    "invalid type"을 반환합니다.

ECMAScript 값 input으로 값을 multiEntry 키로 변환하기 단계. 결과는 , "invalid value", "invalid type" 또는 예외 발생일 수 있습니다.

  1. inputArray exotic object라면:

    1. len? ToLength( ? Get(input, "length"))로 설정합니다.

    2. seenset으로 새로 만들고 input만 포함합니다.

    3. keys를 새로운 빈 목록(list)으로 설정합니다.

    4. index를 0으로 설정합니다.

    5. indexlen보다 작을 동안:

      1. entryGet(input, index)로 설정합니다.

      2. entryabrupt completion이 아니면:

        1. key값을 키로 변환하기(entry, seen)의 결과로 설정합니다.

        2. key가 "invalid value", "invalid type" 또는 abrupt completion이 아니고, keysitem같은 것이 없으면, append keykeys에 추가합니다.

      3. index를 1 증가시킵니다.

    6. array key를 새로 만들어 valuekeys로 반환합니다.

  2. 그 외에는 값을 키로 변환하기(input)의 결과를 반환합니다. 예외 발생 시 다시 던집니다.

NOTE: 이 단계들은 값을 키로 변환하기와 유사하지만, 최상위 값이 Array라면 변환 불가 멤버는 무시되고, 중복이 제거됩니다.

예를 들어, 값 [10, 20, null, 30, 20]array key로 변환되며 subkeys는 10, 20, 30입니다.

8. 개인정보 보호 고려사항

이 섹션은 규범적이지 않습니다.

8.1. 사용자 추적

서드파티 호스트(혹은 여러 사이트에 콘텐츠를 배포할 수 있는 객체)는 클라이언트 측 데이터베이스에 저장된 고유 식별자를 사용해 사용자를 여러 세션에 걸쳐 추적하고, 사용자의 활동 프로필을 구축할 수 있습니다. 사용자의 실제 id 객체를 아는 사이트(예: 인증된 자격 증명을 요구하는 전자상거래 사이트)와 결합되면, 억압적인 집단이 순수하게 익명적인 웹 이용 환경보다 더 정확하게 개인을 타겟팅할 수 있습니다.

사용자 추적 위험을 완화할 수 있는 여러 기술들이 있습니다:

서드파티 저장소 차단

사용자 에이전트는 데이터베이스 객체에 대한 접근을 탐색 컨텍스트의 최상위 문서 도메인에서 유래한 스크립트로 제한할 수 있습니다. 예를 들면, 다른 도메인에서 iframe에 실행되는 페이지의 API 접근을 거부할 수 있습니다.

저장 데이터의 만료

사용자 에이전트는 저장된 데이터를 일정 기간 후에 자동으로 삭제할 수 있습니다.

이렇게 하면 사이트가 사용자를 여러 세션에 걸쳐 추적할 수 있는 능력이 제한되지만, 사용자가 사이트에 인증(예: 구매, 서비스 로그인 등)을 할 때만 추적이 가능합니다.

하지만 이로 인해 사용자의 데이터가 위험에 처할 수 있습니다.

영구 저장소를 쿠키처럼 취급하기

사용자 에이전트는 데이터베이스 기능을 HTTP 세션 쿠키와 강하게 연관 지어 사용자에게 보여줘야 합니다. [COOKIES]

이렇게 하면 사용자가 이러한 저장소를 경계심을 가지고 바라볼 수 있습니다.

사이트별 데이터베이스 접근 허용 목록

사용자 에이전트는 사이트가 해당 기능을 사용하기 전에 사용자가 데이터베이스 접근을 승인하도록 요구할 수 있습니다.

서드파티 저장소의 출처 명시

사용자 에이전트는 제3자 출처로부터 데이터가 저장되게 한 사이트의 출처를 기록할 수 있습니다.

이 정보가 영구 저장소 내 데이터 표시에 사용된다면, 사용자가 어떤 부분을 삭제할지 판단할 수 있습니다. 블록리스트("이 데이터를 삭제하고 이 도메인에 데이터 저장을 영구히 차단")와 결합하면, 사용자는 신뢰하는 사이트만 영구 저장소를 사용할 수 있도록 제한할 수 있습니다.

공유 블록리스트

사용자 에이전트는 사용자가 자신의 영구 저장소 도메인 블록리스트를 공유할 수 있게 허용할 수 있습니다.

이렇게 하면 커뮤니티가 함께 개인정보를 보호할 수 있습니다.

이러한 제안들은 이 API가 사용자 추적에 쉽게 사용되는 것을 방지하지만, 완전히 차단하지는 않습니다. 단일 도메인 내에서는 사이트가 세션 중 사용자를 계속 추적할 수 있고, 이 정보를 제3자에게 이름, 신용카드 번호, 주소 등 식별 정보를 함께 전달할 수 있습니다. 만약 제3자가 여러 사이트와 협력해 정보를 얻는다면, 여전히 프로필이 생성될 수 있습니다.

하지만 사용자 에이전트의 협력 없이도 어느 정도의 사용자 추적이 가능합니다. 예를 들어, URL의 세션 식별자를 사용하는 것은 이미 무해한 목적으로도 흔히 사용되며, 사용자 추적에 손쉽게 전용될 수 있습니다(심지어 소급적으로도). 이렇게 얻은 정보는 방문자의 IP 주소나 기타 사용자별 데이터(예: user-agent 헤더와 설정값)를 활용해 여러 세션을 하나의 사용자 프로필로 조합할 수 있습니다.

영구 저장소의 사용자 인터페이스가 이 명세에서 설명된 영구 저장소의 데이터를 HTTP 세션 쿠키와 별도로 보여준다면, 사용자는 한쪽의 데이터만 삭제하는 경향이 있습니다. 이렇게 되면 사이트가 두 기능을 서로 보완적인 백업으로 사용해 사용자의 개인정보 보호 노력을 무력화할 수 있습니다.

8.3. 데이터의 민감성

사용자 에이전트는 영구 저장된 데이터를 잠재적으로 민감한 것으로 취급해야 합니다. 이메일, 일정, 건강 기록이나 기타 기밀 문서가 이 메커니즘에 저장될 수도 있습니다.

이러한 이유로, 사용자 에이전트는 데이터를 삭제할 때, 즉시 기저 저장소에서도 삭제되도록 해야 합니다.

9. 보안 고려사항

9.1. DNS 스푸핑 공격

DNS 스푸핑 공격의 가능성 때문에, 특정 도메인에서 왔다고 주장하는 호스트가 실제로 해당 도메인인지 보장할 수 없습니다. 이를 완화하기 위해 페이지는 TLS를 사용할 수 있습니다. TLS를 사용하는 페이지는 동일한 도메인으로 인증된 TLS 페이지만 데이터베이스에 접근할 수 있다는 점을 확신할 수 있습니다.

9.2. 디렉터리 간 공격

하나의 호스트명을 공유하는 여러 저작자는, 예를 들어 geocities.com에 콘텐츠를 올리는 사용자들은, 하나의 데이터베이스 집합을 공유하게 됩니다.

경로명별 접근 제한 기능은 없습니다. 따라서 공유 호스트의 저작자는 이런 기능 사용을 피하는 것이 좋습니다. 다른 저작자가 데이터를 읽거나 덮어쓰기 매우 쉽기 때문입니다.

NOTE: 경로 제한 기능이 제공된다고 해도, 일반적인 DOM 스크립팅 보안 모델에서는 이러한 보호를 쉽게 우회해 모든 경로에서 데이터를 접근할 수 있게 됩니다.

9.3. 구현 위험

이 영구 저장소 기능을 구현할 때 주요 위험은 적대적 사이트가 다른 도메인의 정보를 읽거나, 적대적 사이트가 정보를 기록해서 다른 도메인에서 읽히게 하는 것입니다.

서드파티 사이트가 자신의 도메인에서 읽을 수 없는 데이터를 읽게 하면 정보 누출이 발생합니다. 예를 들면, 한 도메인에서 사용자의 쇼핑 위시리스트가 다른 도메인에서 타겟 광고에 사용될 수 있고, 워드프로세서 사이트에 저장된 작업 중인 기밀 문서가 경쟁사 사이트에서 열람될 수 있습니다.

서드파티 사이트가 다른 도메인의 영구 저장소에 데이터를 기록하게 하면 정보 위조가 발생할 수 있는데, 이것도 매우 위험합니다. 예를 들어, 악의적인 사이트가 사용자의 위시리스트에 레코드를 추가하거나, 사용자의 세션 식별자를 악의적인 사이트가 추적 가능한 값으로 설정할 수 있습니다.

따라서, 이 명세에서 설명된 스토리지 키 분할 모델을 엄격히 따르는 것이 사용자 보안에 중요합니다.

호스트명이나 데이터베이스명이 파일 시스템 경로를 구성하는 데 사용된다면, 반드시 적절히 이스케이프 처리해야 합니다. 그래야 공격자가 "../"와 같은 상대 경로를 사용해 다른 스토리지 키의 정보를 접근하는 것을 막을 수 있습니다.

9.4. 영구성 위험

실제 구현은 데이터를 비휘발성 저장 매체에 영구 저장합니다. 데이터는 저장 시 직렬화되고, 검색 시 역직렬화됩니다. 직렬화 형식의 상세는 사용자 에이전트마다 다릅니다. 사용자 에이전트는 시간이 지나며 직렬화 형식을 변경할 수 있습니다. 예를 들어, 새로운 데이터 타입을 처리하거나 성능을 개선하기 위해 형식이 업데이트될 수 있습니다. 이 명세의 운영 요구를 만족시키려면, 구현은 반드시 이전 직렬화 형식도 적절히 처리해야 합니다. 이전 데이터를 제대로 처리하지 않으면 보안 문제가 발생할 수 있습니다. 직렬화 관련 기본적인 문제 외에도, 직렬화된 데이터가 사용자 에이전트의 새로운 버전에서는 유효하지 않은 가정을 포함할 수도 있습니다.

실제 예로, RegExp 타입이 있습니다. StructuredSerializeForStorage 연산은 RegExp 객체를 직렬화할 수 있습니다. 일반적인 사용자 에이전트는 정규식을 네이티브 머신 명령어로 컴파일하며, 입력 데이터 전달 및 결과 반환 방법에 대한 가정을 갖고 있습니다. 만약 이러한 내부 상태가 데이터베이스에 저장되는 데이터의 일부로 직렬화된다면, 나중에 역직렬화할 때 여러 문제가 발생할 수 있습니다. 예를 들어, 데이터 전달 방식이 변경될 수 있습니다. 컴파일러 출력의 보안 버그가 사용자 에이전트 업데이트로 수정되었더라도, 직렬화된 내부 상태에는 그대로 남아 있을 수 있습니다.

사용자 에이전트는 반드시 이전 데이터를 적절히 식별하고 처리해야 합니다. 한 가지 방법은 직렬화 형식에 버전 식별자를 포함하고, 이전 데이터를 만났을 때 스크립트에서 볼 수 있는 상태만으로 내부 상태를 재구성하는 것입니다.

10. 접근성 고려사항

이 섹션은 규범적이지 않습니다.

이 명세에서 설명하는 API는 접근성 고려가 제한적입니다:

API는 구조화된 콘텐츠 저장을 허용합니다. 텍스트 콘텐츠는 문자열로 저장할 수 있습니다. 개발자들은 이미지, 오디오와 같은 비텍스트 대체 콘텐츠도 Blob, File, 또는 ImageData 객체로 저장할 수 있습니다. 동적 콘텐츠 애플리케이션을 만드는 개발자는 다양한 기술과 필요를 가진 사용자가 콘텐츠에 접근할 수 있도록 해야 합니다.

API 자체는 특정 메커니즘을 정의하지 않지만, 구조화된 콘텐츠 저장을 통해 개발자가 다양한 언어 대안을 담은 국제화된 콘텐츠를 저장할 수 있습니다.

API는 사용자 에이전트가 API와 상호작용할 수 있는 사용자 인터페이스를 생성하도록 정의하거나 요구하지 않습니다. 사용자 에이전트는 선택적으로 API를 지원하는 UI 요소를 제공할 수 있습니다. 예시로, 추가 저장소 할당량이 필요할 때 사용자에게 프롬프트를 띄우거나, 특정 웹사이트의 저장소 사용량을 관찰하는 기능, 또는 API 저장소 전용 툴(레코드 검사, 수정, 삭제 등)이 있습니다. 이러한 UI 요소는 접근성 도구를 고려해 설계되어야 합니다. 예를 들어, 사용된 저장소 할당량 비율을 그래픽으로 표현하는 UI는 스크린 리더와 같은 도구에도 동일한 데이터를 제공해야 합니다.

11. 개정 이력

이 섹션은 규범적이지 않습니다.

다음은 이 명세의 지난 발행 이후 변경사항에 대한 안내 요약입니다. 전체 개정 이력은 여기에서 볼 수 있습니다. 제1판의 개정 이력은 해당 문서의 개정 이력을, 제2판의 개정 이력은 해당 문서의 개정 이력을 참고하세요.

12. 감사의 글

이 섹션은 규범적이지 않습니다.

제1판의 원 저자인 Nikunj Mehta와, 추가 편집자인 Jonas Sicking, Eliot Graff, Andrei Popescu, Jeremy Orlow에게 특별히 감사드립니다.

Garret Swart는 이 명세의 설계에 매우 큰 영향을 주었습니다.

Tab Atkins, Jr.에게 Bikeshed 명세 작성 도구를 만들고 유지해 준 것과, 일반 저작 조언에 대해 감사드립니다.

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; et al. 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; et al. 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?