이 문서는 인덱스드 데이터베이스 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-트리 데이터 구조를 이용해 구현됩니다.
"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을 저장할 수 있는 문자열로 매핑하기 위해 이스케이프 메커니즘 등을 사용할 수 있습니다.
names names에서 정렬된 name 목록 생성을 하려면 다음 절차를 실행합니다:
-
sorted를 names의 오름차순 정렬로, code unit less than 알고리즘을 사용하여 만듭니다.
-
sorted에 연결된 새로운
DOMStringList
를 반환합니다.
자세히 보기
이는sort()
메서드를 Array
의
String
에
적용한 결과와 같습니다.
이 정렬은 각 문자열의 16비트 코드 단위를 비교하여 매우 효율적이고 일관적이며 결정적인 정렬 순서를 만듭니다. 결과 목록은 특정
알파벳이나 사전적 순서와 일치하지 않으며, 특히 서러게이트 페어로 표현된 코드 포인트에 대해서는 더욱 그렇습니다.
2.1. 데이터베이스
각 storage key는 연관된 database 집합을 가집니다. database는 0개 이상의 오브젝트 스토어를 가지며, 데이터베이스에 저장된 데이터를 보관합니다.
database는 특정 storage key 내에서 식별되는 name을 가집니다. name은 name이며, 데이터베이스의 생명주기 동안 변하지 않습니다.
database는 version을 가집니다. 데이터베이스가 처음 생성될 때 version은 0(영)입니다.
참고: 각 database는 한 번에 하나의 버전만 가집니다; database가 여러 버전으로 동시에 존재할 수 없습니다. 버전을 변경하는 유일한 방법은 업그레이드 트랜잭션을 사용하는 것입니다.
database는 최대 하나의 업그레이드 트랜잭션이 연관될 수 있으며, 이는 null 또는 업그레이드 트랜잭션입니다. 처음에는 null입니다.
2.1.1. 데이터베이스 연결
스크립트는 database에 직접적으로 상호작용하지 않습니다. 대신, 스크립트는 connection을 통해 간접적으로 접근합니다. connection 오브젝트는 해당 database의 객체들을 조작할 수 있습니다. 또한 트랜잭션을 획득하는 유일한 방법입니다. database에 대해 트랜잭션을 얻으려면 connection을 사용해야 합니다.
database를 열면 connection이 생성됩니다. 하나의 database에 여러 connection이 동시에 존재할 수 있습니다.
connection은 해당 글로벌 스코프에서 열린 connection의 storage key와 연관된 database에만 접근할 수 있습니다.
참고:
이는 Document
의
domain
변경에는 영향을 받지 않습니다.
connection은 version을 가지며, 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로 설정하여 실행해야 합니다.
connection은 object store 집합을 가지며, 이는 connection이 생성될 때 연관된 database의 오브젝트 스토어 집합으로 초기화됩니다. 집합의 내용은 업그레이드 트랜잭션이 live 상태일 때만 변경됩니다.
connection의 get the parent 알고리즘은 null을 반환합니다.
IDBDatabase의 열린 connection에서
versionchange
유형의 이벤트가,
데이터베이스를 업그레이드하거나 삭제하려는 시도가 있을 때 발생합니다. 이 이벤트를 통해 connection이 닫혀 업그레이드나 삭제가 진행될 수 있도록 합니다.
IDBDatabase의 connection에서 close
유형의 이벤트가, 연결이 비정상적으로 닫힘 상태가 될 때 발생합니다.
2.2. 오브젝트 스토어
오브젝트 스토어는 데이터베이스에 데이터를 저장하기 위한 기본 저장 메커니즘입니다.
각 데이터베이스는 오브젝트 스토어 집합을 가집니다.
오브젝트 스토어 집합은 변경될 수 있지만, 업그레이드 트랜잭션을
통해서만 변경할 수 있습니다.
즉, upgradeneeded
이벤트에 응답하여 변경됩니다. 새로운 데이터베이스가 생성되면 오브젝트 스토어는 포함되어 있지 않습니다.
오브젝트 스토어는 레코드 목록을 가지며, 오브젝트 스토어에 저장된 데이터를 보관합니다. 각 레코드는 키와 값으로 구성됩니다. 목록은 키에 따라 오름차순으로 정렬됩니다. 하나의 오브젝트 스토어에 동일한 키를 가진 레코드가 여러 개 존재할 수 없습니다.
오브젝트 스토어는 name을 가지며, 이는 name입니다. 언제나 해당 데이터베이스 내에서 고유합니다.
오브젝트 스토어는 선택적으로 키 경로를 가질 수 있습니다. 오브젝트 스토어가 키 경로를 가지면 인라인 키를 사용한다고 하며, 그렇지 않으면 아웃라인 키를 사용한다고 합니다.
2.2.1. 오브젝트 스토어 핸들
스크립트는 오브젝트 스토어에 직접적으로 상호작용하지 않습니다. 대신, 트랜잭션 내에서, 스크립트는 오브젝트 스토어 핸들을 통해 간접적으로 접근합니다.
오브젝트 스토어 핸들은 연관된 오브젝트 스토어 와 연관된 트랜잭션을 가집니다. 여러 핸들이 서로 다른 트랜잭션에서 동일한 오브젝트 스토어와 연관될 수 있지만, 하나의 트랜잭션 내에서 특정 오브젝트 스토어에 연관된 오브젝트 스토어 핸들은 반드시 하나여야 합니다.
오브젝트 스토어 핸들은 인덱스 집합을 가집니다. 이는 핸들이 생성될 때 연관된 오브젝트 스토어를 참조하는 인덱스 집합으로 초기화됩니다. 집합의 내용은 업그레이드 트랜잭션이 live 상태일 때만 변경됩니다.
오브젝트 스토어 핸들은 name을 가지며, 핸들이 생성될 때 연관된 오브젝트 스토어의 name으로 초기화됩니다. 이름은 업그레이드 트랜잭션이 live 상태일 때만 변경될 수 있습니다.
2.3. 값
각 레코드는 값과 연관됩니다. 사용자 에이전트는 모든 직렬화 가능한 객체를 지원해야 합니다. 여기에는 String
원시 값과 Date
객체, Object
및 Array
인스턴스, File
객체, Blob
객체, ImageData
객체 등이 포함됩니다. 레코드 값은 참조가 아니라 값 자체로 저장 및 조회됩니다.
이후 값의 변경은 데이터베이스에 저장된 레코드에 영향을 주지 않습니다.
레코드 값은 Records이며, StructuredSerializeForStorage 연산의 출력입니다.
2.4. 키
인덱싱된 데이터베이스에 저장된 레코드를 효율적으로 조회하기 위해, 각 레코드는 자신의 키를 기준으로 정렬됩니다.
키는 연관된 타입을 가지며, 다음 중 하나입니다: number, date, string, binary, array.
키에는 연관된 값도 있으며,
이는 타입에 따라 다음 중 하나입니다:
타입이 number 또는 date이면 unrestricted double
,
타입이 string이면 DOMString
,
타입이 binary이면 바이트 시퀀스,
타입이 array이면 다른 키의 리스트입니다.
ECMAScript [ECMA-262] 값은 값을 키로 변환하는 절차를 따라 키로 변환할 수 있습니다.
-
Number
원시 값(NaN 제외). Infinity와 -Infinity 포함. -
Date
객체([[DateValue]] 내부 슬롯이 NaN이 아닌 경우). -
String
원시 값. -
ArrayBuffer
객체(또는Uint8Array
와 같은 버퍼 뷰). -
Array
객체(모든 항목이 정의되어 있고, 각 항목이 유효한 키이며, 직접 또는 간접적으로 자기 자신을 포함하지 않을 때). 빈 배열도 포함. 배열은 다른 배열을 포함할 수 있습니다.
다른 ECMAScript 값을 키로 변환하려고 하면 실패합니다.
배열 키는 키 중 타입이 array인 것입니다. 하위 키는 배열 키의 항목이며, 배열 키의 값입니다.
두 키 비교 a와 b를 비교하려면 다음 절차를 진행합니다:
-
ta를 a의 타입으로 한다.
-
tb를 b의 타입으로 한다.
-
ta와 tb가 다르면 다음을 진행한다:
-
ta가 array면 1을 반환한다.
-
tb가 array면 -1을 반환한다.
-
ta가 binary면 1을 반환한다.
-
tb가 binary면 -1을 반환한다.
-
ta가 string이면 1을 반환한다.
-
tb가 string이면 -1을 반환한다.
-
ta가 date면 1을 반환한다.
-
Assert: tb가 date이다.
-
-1을 반환한다.
-
-
va를 a의 값으로 한다.
-
vb를 b의 값으로 한다.
-
ta에 따라 분기한다:
- number
- date
-
-
va가 vb보다 크면 1을 반환한다.
-
va가 vb보다 작으면 -1을 반환한다.
-
0을 반환한다.
-
- string
-
-
va가 code unit less than vb이면 -1을 반환한다.
-
vb가 code unit less than va이면 1을 반환한다.
-
0을 반환한다.
-
- binary
-
-
va가 byte less than vb이면 -1을 반환한다.
-
vb가 byte less than va이면 1을 반환한다.
-
0을 반환한다.
-
- array
- number
키 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. 키 경로
키 경로는 키를 값에서 추출하는 방법을 정의하는 문자열 또는 문자열의 리스트입니다. 유효한 키 경로는 다음 중 하나입니다:
-
빈 문자열.
-
식별자, 즉 IdentifierName 생성 규칙을 따르는 문자열입니다. ECMAScript 언어 명세 [ECMA-262]를 참고하세요.
-
여러 개의 식별자가 마침표(U+002E FULL STOP)로 구분된 문자열.
-
위 요구사항을 모두 만족하는 문자열만 포함된 비어 있지 않은 리스트.
참고: 키 경로 내에는 공백이 허용되지 않습니다.
키 경로 값은 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
인 레코드가 포함됩니다.
인덱스의 레코드는 참조 값을 가진다고 합니다. 이는 인덱스의 참조된 오브젝트 스토어에서 인덱스 레코드의 값과 동일한 키를 가진 레코드의 값입니다. 위 예시에서, 인덱스의 키 key가 Y이고 값이 X인 레코드는 참조 값이 A입니다.
참고: 인덱스의 각 레코드는 인덱스의 참조된 오브젝트 스토어의 단 하나의 레코드만 참조합니다. 하지만 인덱스에는 한 오브젝트 스토어의 동일한 레코드를 참조하는 여러 레코드가 있을 수 있으며, 오브젝트 스토어의 특정 레코드를 참조하는 인덱스 레코드가 없을 수도 있습니다.
인덱스의 레코드는 항상 레코드의 키에 따라 정렬됩니다. 하지만 오브젝트 스토어와 달리, 하나의 인덱스에 동일한 키를 가진 여러 레코드가 있을 수 있습니다. 이러한 레코드는 추가로 인덱스의 레코드의 값(즉, 참조된 오브젝트 스토어의 레코드의 키)에 따라 정렬됩니다.
인덱스는 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를 가지며, 트랜잭션이 중단될 때 설정됩니다.
abort()
에 의해 설정됩니다.
트랜잭션의 get the parent 알고리즘은 해당 트랜잭션의 connection을 반환합니다.
읽기 전용 트랜잭션은
트랜잭션 중 mode가 "readonly
"인
것입니다.
읽기/쓰기 트랜잭션
은 트랜잭션 중 mode가 "readwrite
"인
것입니다.
2.7.1. 트랜잭션 생명주기
트랜잭션에는 상태가 있으며, 다음 중 하나입니다:
- active
-
트랜잭션이 처음 생성될 때, 그리고 트랜잭션과 연관된 요청에서 이벤트가 디스패치되는 동안 이 상태가 됩니다.
이 상태일 때는 트랜잭션에 대해 새로운 요청을 할 수 있습니다.
- inactive
-
트랜잭션이 생성된 후 제어가 이벤트 루프로 돌아오거나, 이벤트가 디스패치되지 않을 때 이 상태가 됩니다.
이 상태일 때는 트랜잭션에 대해 요청을 할 수 없습니다.
- committing
-
트랜잭션과 연관된 모든 요청이 완료되면, 트랜잭션은 커밋을 시도하면서 이 상태가 됩니다.
이 상태일 때는 트랜잭션에 대해 요청을 할 수 없습니다.
- finished
-
트랜잭션이 커밋되거나 중단(abort)된 후 이 상태가 됩니다.
이 상태일 때는 트랜잭션에 대해 요청을 할 수 없습니다.
트랜잭션은 단기간만 유지되는 것이 권장됩니다. 이는 아래의 자동 커밋 기능에 의해 장려됩니다.
참고: 작성자는 트랜잭션을 live 상태로 오래 유지시킬 수도 있습니다. 그러나 이런 사용 패턴은 사용자 경험 저하를 유발할 수 있으므로 권장되지 않습니다.
트랜잭션의 생명주기는 다음과 같습니다:
-
구현체가 트랜잭션의 scope와 mode의 제약을 아래 트랜잭션 스케줄링에 따라 만족시킬 수 있을 때, 데이터베이스 작업을 큐에 추가해서 트랜잭션을 비동기로 시작해야 합니다.
트랜잭션이 시작되면, 구현체는 트랜잭션에 대해 요청된 요청을 실행할 수 있습니다. 요청은 트랜잭션에 대해 요청된 순서대로 실행되어야 하며, 결과 역시 해당 트랜잭션에 대해 요청된 순서대로 반환되어야 합니다. 서로 다른 트랜잭션의 요청 결과 반환 순서는 보장되지 않습니다.
참고: 트랜잭션의 mode는 서로 다른 트랜잭션의 요청이 어떤 순서로 실행되더라도 데이터베이스에 저장되는 결과 데이터에 영향을 주지 않도록 보장합니다.
-
트랜잭션과 연관된 각 요청이 처리되면,
success
또는error
event가 발생합니다. 이벤트가 디스패치되는 동안 트랜잭션의 state는 active가 되어 추가 요청을 트랜잭션에 할 수 있습니다. 이벤트 디스패치가 끝나면 state는 다시 inactive가 됩니다. -
트랜잭션은 중단(abort)될 수 있으며, finished 상태가 되기 전까지 언제든 중단될 수 있습니다. 이는 트랜잭션이 active가 아니거나 아직 시작되지 않은 경우에도 가능합니다.
abort()
를 명시적으로 호출하면 중단(abort)이 시작됩니다. 스크립트에서 처리되지 않은 요청이 실패한 경우에도 중단이 시작됩니다.트랜잭션이 중단되면, 구현체는 해당 트랜잭션 동안 데이터베이스에 이루어진 모든 변경사항을 롤백(undo)해야 합니다. 이는 오브젝트 스토어의 내용 변경뿐 아니라 오브젝트 스토어와 인덱스의 추가/삭제도 포함됩니다.
-
구현체는 트랜잭션이 inactive이고, 트랜잭션에 대해 요청된 모든 요청이 완료되고 결과가 처리되었으며, 새로운 요청이 추가되지 않았고 트랜잭션이 중단되지 않았을 때 커밋을 시도해야 합니다.
commit()
를 명시적으로 호출하면 스크립트에서 요청 결과를 기다리지 않고 커밋을 시작합니다.커밋할 때 트랜잭션의 state는 committing이 됩니다. 구현체는 트랜잭션에 대해 요청된 변경사항을 데이터베이스에 원자적으로 기록해야 하며, 즉 모든 변경사항을 기록하거나, 오류(예: 디스크 기록 오류)가 발생하면 아무 변경도 기록하지 않아야 하며, 트랜잭션 중단 절차를 따라야 합니다.
구현체는 트랜잭션이 active일 때 언제든 요청을 추가할 수 있도록 해야 합니다. 트랜잭션이 아직 시작되지 않은 경우에도 마찬가지입니다. 트랜잭션이 시작되기 전에는 요청을 실행하지 않아야 하지만, 요청과 그 순서는 반드시 기록해 두어야 합니다.
트랜잭션은 live 상태로, 생성된 순간부터 state가 finished가 될 때까지입니다.
Indexed Database 트랜잭션 정리를 하려면 다음 절차를 실행합니다. 트랜잭션이 정리되었으면 true를, 그렇지 않으면 false를 반환합니다.
-
현행 이벤트 루프와 cleanup event loop가 일치하는 트랜잭션이 하나도 없으면 false를 반환합니다.
-
현행 이벤트 루프와 cleanup event loop가 일치하는 각 트랜잭션 transaction에 대해:
-
transaction의 cleanup event loop를 지웁니다.
-
true를 반환합니다.
참고:
이 단계는 [HTML]에서 호출됩니다. 이는 스크립트에서
transaction()
을 호출하여 생성한 트랜잭션을, 스크립트 호출 작업이 완료되면 비활성화하도록 보장합니다. 각 트랜잭션마다 최대 한 번만 실행됩니다.
IDBTransaction에서 complete
타입 이벤트는
트랜잭션이
성공적으로 커밋된 경우
발생합니다.
IDBTransaction에서 abort
타입 이벤트는
트랜잭션이
중단된 경우 발생합니다.
2.7.2. 트랜잭션 스케줄링
다음 제약들은 트랜잭션이 언제 시작될 수 있는지를 정의합니다:
-
읽기 전용 트랜잭션 tx는 다음 조건을 모두 만족하는 읽기/쓰기 트랜잭션이 없을 때 시작할 수 있습니다:
-
tx보다 먼저 생성되었고,
-
tx와 scope가 겹치며,
-
아직 완료되지 않은 트랜잭션.
-
-
읽기/쓰기 트랜잭션 tx는 다음 조건을 모두 만족하는 트랜잭션이 없을 때 시작할 수 있습니다:
-
tx보다 먼저 생성되었고,
-
tx와 scope가 겹치며,
-
아직 완료되지 않은 트랜잭션.
-
구현체는 추가적인 제약을 둘 수 있습니다. 예를 들어, 구현체는 시작되는 scope가 겹치지 않는 읽기/쓰기 트랜잭션을 병렬로 실행할 필요는 없으며, 동시에 시작되는 트랜잭션의 수를 제한할 수도 있습니다.
-
임의의 수의 읽기 전용 트랜잭션이 동시에 시작될 수 있으며, scope가 겹치는 경우에도 가능합니다.
-
읽기 전용 트랜잭션이 live 상태인 동안, 해당 트랜잭션을 통해 요청으로 반환되는 데이터는 항상 일정하게 유지됩니다. 즉, 동일한 데이터를 읽는 두 요청은 데이터가 있을 때는 동일한 결과, 데이터가 없을 때는 데이터 없음 결과를 반환합니다.
-
읽기/쓰기 트랜잭션은 해당 트랜잭션을 통해서만 오브젝트 스토어의 변경에 영향을 받습니다. 구현체는 다른 트랜잭션이 오브젝트 스토어 내용을 읽기/쓰기 트랜잭션의 scope 내에서 수정하지 않도록 보장합니다. 또한 읽기/쓰기 트랜잭션이 성공적으로 완료될 시 해당 트랜잭션으로 작성된 변경사항은 병합 충돌 없이 데이터베이스에 커밋될 수 있도록 보장합니다.
-
여러 읽기/쓰기 트랜잭션이 동일한 오브젝트 스토어에 접근하려고 하면(즉, scope가 겹치는 경우), 먼저 생성된 트랜잭션이 오브젝트 스토어에 첫 번째로 접근하며, 해당 트랜잭션이 완료될 때까지 오브젝트 스토어에 접근할 수 있는 유일한 트랜잭션입니다.
-
읽기/쓰기 트랜잭션 이후에 생성된 트랜잭션은 해당 읽기/쓰기 트랜잭션에서 작성된 변경사항을 볼 수 있습니다. 예를 들어, 읽기/쓰기 트랜잭션 A가 먼저 생성되고, 이후 트랜잭션 B가 생성되며 두 트랜잭션이 scope가 겹치면 트랜잭션 B는 A에서 변경된 오브젝트 스토어를 볼 수 있습니다. 또한 트랜잭션 B는 트랜잭션 A가 완료될 때까지 해당 겹치는 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 오브젝트가 있습니다.
요청에는 result와 error가 있으며, done 플래그가 true가 되기 전까지는 접근할 수 없습니다.
요청에는 transaction이 있으며, 초기값은 null입니다. 요청이 트랜잭션에 추가될 때 설정됩니다. 트랜잭션에 대해 요청을 비동기적으로 실행 단계에서 설정됩니다.
요청이 만들어지면, 새로운 요청이 반환되며 done 플래그는
false입니다. 요청이 성공적으로 완료되면 done 플래그가 true가 되고, result가 해당 요청의 결과로 설정됩니다. 그리고 success
타입 이벤트가 요청에 발생합니다.
작업 중 오류가 발생하면 요청의 done
플래그가 true가 되고, error가 오류로 설정되며, error
타입 이벤트가 요청에 발생합니다.
요청의 get the parent 알고리즘은 요청의 transaction을 반환합니다.
참고:
요청은 일반적으로 재사용되지 않지만, 예외가 있습니다. 커서를
반복(iterate)할 때, 반복의 성공은 커서를 열 때 사용한 동일한 요청 오브젝트로 보고됩니다. 그리고 업그레이드 트랜잭션이 필요한 경우, 같은 open request가 upgradeneeded
이벤트와 최종 open 작업 결과 모두에 사용됩니다. 어떤 경우에는 요청의 done 플래그가 false로 설정된 뒤 다시 true가 되며, result가 변경되거나 error가 설정될 수 있습니다.
2.8.1. Open 요청
open request는 요청 중, connection을 열거나 데이터베이스를 삭제할 때 사용하는 특수 타입입니다.
success
및 error
이벤트 외에도,
blocked
및 upgradeneeded
이벤트가 open
request에 발생하여 진행 상황을 알릴 수 있습니다.
source가 open request일 때는 항상 null입니다.
transaction이 open
request일 때는 upgradeneeded
이벤트가 발생하지 않는 한 null입니다.
open request의 get the parent 알고리즘은 null을 반환합니다.
2.8.2. 연결 큐
Open request는 connection queue에서 처리됩니다. 이 큐에는 해당 open request와 연관된 storage key 및 name이 모두 포함됩니다. 큐에 추가된 connection queue의 요청들은 순서대로 처리되며, 각 요청은 완료되어야 다음 요청을 처리할 수 있습니다. open request는 다른 connection에 의해 블록될 수 있으며, 해당 connection이 닫힘 상태가 되어야 요청이 완료되어 이후 요청이 처리될 수 있습니다.
참고: connection queue는 현행 표준의 task queue가 아니며, 요청들은 특정 브라우징 컨텍스트와 상관없이 처리됩니다. 완료된 open request에 이벤트 전달은 여전히 task queue 와 해당 요청이 만들어진 컨텍스트의 이벤트 루프를 통해 진행됩니다.
2.9. 키 범위
레코드는 오브젝트 스토어 및 인덱스에서 키 또는 키 범위를 이용하여 조회할 수 있습니다. 키 범위는 키로 사용되는 데이터 타입에 대한 연속된 구간입니다.
키 범위에는 연관된 하한(null 또는 키)이 있습니다.
키 범위에는 연관된 상한(null 또는 키)이 있습니다.
키 범위에는 연관된 하한 개방 플래그가 있습니다. 별도 명시가 없는 한 false입니다.
키 범위에는 연관된 상한 개방 플래그가 있습니다. 별도 명시가 없는 한 false입니다.
키 범위가 특정 키만 포함한다면, 하한과 상한이 모두 key와 같습니다.
key가 키 범위에 포함되어 있다고 하려면 range에 대해 다음 두 조건을 모두 만족해야 합니다:
-
range의 하한이 null이거나 key보다 작거나, 혹은 같고 range의 하한 개방 플래그가 false일 때입니다.
-
range의 상한이 null이거나 key보다 크거나, 혹은 같고 range의 상한 개방 플래그가 false일 때입니다.
무한 키 범위는 키 범위에서 하한과 상한이 모두 null인 경우입니다. 모든 키는 무한 키 범위 내에 포함됩니다.
값을 키 범위로 변환하려면 value와 (선택적) null disallowed flag를 받아 다음 절차를 실행합니다:
잠재적으로 유효한 키 범위는 ECMAScript 값 중 키 범위로 변환될 수 있는 타입을 가진 값입니다. 해당 값이 실제로 키 범위로 변환될 때 예외가 발생하는지 여부는 중요하지 않습니다.
참고: 예를 들어, detached BufferSource는 잠재적으로 유효한 키 범위이지만 값을 키 범위로 변환에 사용되면 예외가 발생합니다.
ECMAScript value가 잠재적으로 유효한 키 범위인지 판단하려면 다음 절차를 실행합니다:
-
value가 키 범위라면 true를 반환한다.
-
key를 값을 키로 변환 단계와 value로 얻는다.
-
key가 "invalid type"이면 false를 반환한다.
-
그 외에는 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도 가지며, 이는 인덱스에서 직전에 찾은 레코드의 값을 나타냅니다. position과 object store position 모두 다음 적합한 레코드를 찾을 때 사용됩니다.
커서는 key와 value를 가지며, 이는 마지막으로 탐색한 레코드의 키와 값을 나타냅니다.
커서는 got value flag를 가지며, 이 플래그가 false일 때 커서는 다음 값을 로딩 중이거나 범위의 끝에 도달한 상태입니다. true일 때는 커서가 현재 값을 보유하고 다음 값 탐색 준비가 된 상태임을 나타냅니다.
커서의 source가 오브젝트 스토어라면, 커서의 effective object store는 그 오브젝트 스토어이고, effective key는 커서의 position입니다. 커서의 source가 인덱스라면, effective object store는 그 인덱스가 참조하는 오브젝트 스토어이고, effective key는 커서의 object store position입니다.
2.11. 키 생성기
오브젝트 스토어를 생성할 때 키 생성기를 사용하도록 지정할 수 있습니다. 키 생성기는 오브젝트 스토어에 레코드가 삽입될 때 별도로 지정하지 않은 경우 키를 생성하는 데 사용됩니다.
키 생성기에는 현재 숫자가 있습니다. 현재 숫자는 항상 253 (9007199254740992) + 1 이하의 양의 정수입니다. 키 생성기의 현재 숫자의 초기값은 1이며, 연관된 오브젝트 스토어가 생성될 때 설정됩니다. 현재 숫자는 키가 생성될 때마다 증가하며, 명시적으로 키를 지정하면 특정 값으로 갱신될 수 있습니다.
참고: 키 생성기를 사용하는 각 오브젝트 스토어는 별도의 생성기를 가집니다. 즉, 하나의 오브젝트 스토어와 상호작용해도 다른 오브젝트 스토어의 키 생성기는 영향을 받지 않습니다.
키 생성기의 현재 숫자를 수정하는 것은 데이터베이스 작업의 일부로 간주됩니다. 즉, 작업이 실패하여 롤백되면 현재 숫자도 작업 시작 전의 값으로 되돌아갑니다. 이는 키 생성기를 사용할 때 현재 숫자가 1 증가하는 경우와, 레코드를 명시적으로 키 값과 함께 저장하는 경우 모두 적용됩니다.
마찬가지로, 트랜잭션이 중단(abort)되는 경우, 해당 트랜잭션의 scope 내 모든 오브젝트 스토어의 키 생성기 현재 숫자도 트랜잭션 시작 전 값으로 되돌아갑니다.
키 생성기의 현재 숫자는 데이터베이스 작업이 롤백되는 경우를 제외하고는 절대 감소하지 않습니다. 레코드를 오브젝트 스토어에서
삭제해도 오브젝트 스토어의 키 생성기는 영향을 받지 않습니다. clear()
메서드 등으로 모든 레코드를 삭제해도 오브젝트 스토어의 키 생성기 현재 숫자는 영향을 받지 않습니다.
레코드를 저장할 때 키를 명시하지 않으면, 키가 생성됩니다.
오브젝트 스토어 store에서 키 생성하려면 다음 절차를 실행합니다:
레코드를 저장할 때 키를 명시하면, 연관된 키 생성기가 갱신될 수 있습니다.
오브젝트 스토어 store와 key로 키 생성기 갱신 가능성을 판단하려면 다음 절차를 실행합니다:
명시적으로 지정된 type이 number인 키만 키 생성기의 현재 숫자에 영향을 미칩니다. type이 date, array(내부 키에 관계없이), binary, string(숫자로 해석 가능해도)인 키는 키 생성기의 현재 숫자에 영향을 주지 않습니다. type이 number이지만 value가 1보다 작은 키도 현재 숫자에 영향을 주지 않습니다(항상 더 작기 때문).
키 생성기의 현재 숫자가 253 (9007199254740992) 이상이 되면 이후 키
생성기를 사용해 키를 생성하려고 시도하면
"ConstraintError
"
DOMException
이
발생합니다.
명시적으로 키를 지정해서 오브젝트 스토어에 레코드를 삽입하는 것은 가능하지만, 이 경우 키 생성기를 다시 사용하려면 오브젝트 스토어를 삭제하고 새로 만들어야
합니다.
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. 레코드 스냅샷
레코드 스냅샷은 오브젝트 스토어 레코드 또는 인덱스 레코드에서 복사된 키와 값을 포함합니다.
레코드 스냅샷에는 value가 있으며, 이는 값입니다.
참고: 인덱스 레코드의 경우, 스냅샷의 value는 해당 레코드의 참조 값 복사본입니다. 오브젝트 스토어 레코드의 경우, 스냅샷의 value는 레코드 값입니다.
레코드 스냅샷에는 primary key도 있으며, 이는 키입니다.
참고: 인덱스 레코드의 경우, 스냅샷의 primary key는 레코드의 값이며, 이는 인덱스의 참조 오브젝트 스토어 내 해당 레코드의 키입니다. 오브젝트 스토어 레코드의 경우, 스냅샷의 primary key와 key는 동일한 키이며, 이는 레코드의 키입니다.
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 source는 database access task source입니다.
데이터베이스 작업을 큐에 추가하려면 queue a task를 database 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 transaction이 live인 동안에는 upgrade transaction을, 그렇지 않으면 null을 반환합니다. - request .
readyState
result
getter 단계:
-
this의 done flag가 false이면, "
InvalidStateError
"DOMException
을 throw한다.
error
getter 단계:
-
this의 done flag가 false이면, "
InvalidStateError
"DOMException
을 throw한다.
source
getter 단계는
this의 source를 반환하며, source가 설정되지 않았다면 null을
반환합니다.
transaction
getter 단계는
this의 transaction을
반환합니다.
참고: transaction
getter는 open()
등 특정 요청에 대해 null을 반환할 수 있습니다.
readyState
getter 단계는
this의 done flag가 false이면
"pending
"을
반환하고,
그렇지 않으면 "done
"을
반환합니다.
onsuccess
속성은 event handler IDL attribute이며, event handler event type은 success
입니다.
onerror
속성은 event handler IDL attribute이며, event handler event type은 error
입니다.
IDBDatabase
메서드가 open
request를 반환할 때, blocked
와 upgradeneeded
이벤트를 수신할 수 있도록 확장된 인터페이스를 사용합니다.
[Exposed =(Window ,Worker )]interface :
IDBOpenDBRequest IDBRequest { // Event handlers:attribute EventHandler onblocked ;attribute EventHandler onupgradeneeded ; };
onblocked
속성은 event handler IDL attribute이며, event handler event type은 blocked
입니다.
onupgradeneeded
속성은 event handler IDL attribute이며, event handler event type은 upgradeneeded
입니다.
4.2. 이벤트 인터페이스
이 명세는 다음과 같은 커스텀 인터페이스로 이벤트를 발생시킵니다:
[Exposed =(Window ,Worker )]interface :
IDBVersionChangeEvent Event {(
constructor DOMString ,
type optional IDBVersionChangeEventInit = {});
eventInitDict readonly attribute unsigned long long oldVersion ;readonly attribute unsigned long long ?newVersion ; };dictionary :
IDBVersionChangeEventInit EventInit {unsigned long long = 0;
oldVersion unsigned long long ?=
newVersion null ; };
oldVersion
getter 단계는 초기화될 때의 값을 반환합니다. 이는
데이터베이스의 이전 버전을 나타냅니다.
newVersion
getter 단계는 초기화될 때의 값을 반환합니다. 이는
데이터베이스의 새로운 버전을 나타내며, 데이터베이스가 삭제되는 경우 null입니다. 데이터베이스 업그레이드 단계를 참고하세요.
이벤트는 DOM § 2.5 이벤트 생성에 정의된 대로 생성됩니다.
버전 변경 이벤트 발생을 e라는 이름으로 target에 oldVersion과 newVersion을 제공하여 수행하려면 다음 절차를 실행합니다:
-
event를
IDBVersionChangeEvent
를 사용하여 이벤트 생성 결과로 한다. -
event의
type
속성을 e로 설정한다. -
event의
bubbles
및cancelable
속성을 false로 설정한다. -
event의
oldVersion
속성을 oldVersion으로 설정한다. -
event의
newVersion
속성을 newVersion으로 설정한다. -
legacyOutputDidListenersThrowFlag를 false로 한다.
-
event dispatch를 legacyOutputDidListenersThrowFlag와 함께 target에 대해 event로 실행한다.
-
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을 열려고 시도합니다. 요청이 성공하면 request의
result
값이 connection이 됩니다. - request = indexedDB .
open
(name, version) -
지정한 데이터베이스에 version으로 connection을 열려고 시도합니다. 데이터베이스가 더 낮은 버전으로 이미 존재하고,
versionchange
이벤트에 반응하여 닫히지 않는 connection이 열려 있으면 요청이 모두 닫힐 때까지 블록되고, 이후 업그레이드가 발생합니다. 데이터베이스가 이미 더 높은 버전으로 존재하면 요청이 실패합니다. 요청이 성공하면 request의result
값이 connection이 됩니다. - request = indexedDB .
deleteDatabase
(name) -
지정한 데이터베이스를 삭제하려고 시도합니다. 이미 데이터베이스가 존재하고,
versionchange
이벤트에 반응하여 닫히지 않는 connection이 열려 있으면 요청이 모두 닫힐 때까지 블록됩니다. 요청이 성공하면 request의result
값은 null이 됩니다. - result = await indexedDB .
databases
() -
현재 storage key 내 데이터베이스 이름과 버전의 스냅샷을 객체 리스트로 반환하는 promise를 반환합니다.
이 API는 웹 애플리케이션이 이전 버전 사이트의 데이터베이스를 정리하는 등 introspect 용도로 사용할 수 있도록 설계되었습니다. 반환 결과는 스냅샷이므로, 데이터 수집 또는 응답 전달이 이 컨텍스트나 다른 컨텍스트에서 데이터베이스 생성, 업그레이드, 삭제 요청과 어떤 순서로 처리되는지에 대해 보장하지 않습니다.
open(name, version)
메서드 단계는 다음과
같습니다:
-
environment를 this의 relevant settings object로 한다.
-
storageKey를 obtain a storage key를 environment로 실행한 결과로 한다. 실패가 반환되면 throw "
SecurityError
"DOMException
하고, 이 단계를 중단한다. -
request를 새 open request로 한다.
-
다음 단계를 병렬로 실행한다:
-
result를 데이터베이스 연결 열기 결과로 한다. 인자로는 storageKey, name, version(있으면) 또는 없으면 undefined, request를 사용한다.
-
request의 processed flag를 true로 한다.
-
데이터베이스 작업을 큐에 추가하여 다음 단계를 실행한다:
-
result가 에러이면:
-
그렇지 않으면:
참고: 위 단계에서 업그레이드 트랜잭션이 실행된 경우, 이 단계들은 해당 트랜잭션이 종료된 후 실행됩니다. 즉, 다른 버전 업그레이드가 바로 이어질 경우에도, 커넥션에서 먼저 success 이벤트가 발생하여 스크립트가
versionchange
이벤트 리스너를 등록할 기회를 얻도록 보장합니다.success 이벤트 발생이나 error 이벤트 발생 단계를 사용하지 않는 이유는?
이 시점에서 요청에 연관된 트랜잭션이 없으므로, 해당 단계들(이벤트 디스패치 전후에 트랜잭션 활성/비활성화)은 적용되지 않습니다.
-
-
-
request에 대해 새
IDBOpenDBRequest
객체를 반환한다.
deleteDatabase(name)
메서드 단계는 다음과
같습니다:
-
environment를 this의 relevant settings object로 한다.
-
storageKey를 obtain a storage key를 environment로 실행한 결과로 한다. 실패가 반환되면 throw "
SecurityError
"DOMException
하고, 이 단계를 중단한다. -
request를 새 open request로 한다.
-
다음 단계를 병렬로 실행한다:
-
result를 데이터베이스 삭제 결과로 한다. 인자로는 storageKey, name, request를 사용한다.
-
request의 processed flag를 true로 한다.
-
데이터베이스 작업을 큐에 추가하여 다음 단계를 실행한다:
-
result가 에러이면, request의 error를 result로 하고, request의 done flag를 true로 하고, 이벤트 발생을
error
이름으로 request에 대해 실행하며,bubbles
와cancelable
속성은 true로 초기화한다. -
그렇지 않으면, request의 result를 undefined로 하고, request의 done flag를 true로 하고, 버전 변경 이벤트 발생을
success
이름으로 request에 대해 result와 null로 실행한다.success 이벤트 발생이나 error 이벤트 발생 단계를 사용하지 않는 이유는?
이 요청에 연관된 트랜잭션이 없으므로, 해당 단계들(이벤트 디스패치 전후에 트랜잭션 활성/비활성화)은 적용되지 않습니다.또한, 여기서
success
이벤트는IDBVersionChangeEvent
이며,oldVersion
과newVersion
정보가 포함됩니다.
-
-
-
request에 대해 새
IDBOpenDBRequest
객체를 반환한다.
databases()
메서드 단계는 다음과 같습니다:
-
environment를 this의 relevant settings object로 한다.
-
storageKey를 obtain a storage key를 environment로 실행한 결과로 한다. 실패가 반환되면 a promise rejected with "
SecurityError
"DOMException
을 반환한다. -
p를 새 promise로 한다.
-
다음 단계를 병렬로 실행한다:
-
databases를 set of 데이터베이스 in storageKey로 한다. 어떤 이유로든 이를 결정할 수 없다면, 데이터베이스 작업을 큐에 추가하여 p를 적절한 에러로 reject(예: "
UnknownError
"DOMException
)하고, 이 단계를 종료한다. -
result를 새 list로 한다.
-
각 db in databases에 대해:
-
info를 새
IDBDatabaseInfo
딕셔너리로 한다.
-
-
p를 반환한다.
databases()
메서드는 이번 판에서 새로 추가되었습니다.
Chrome 71, Edge 79, Firefox 126, Safari 14에서 지원됩니다.
🚧
- result = indexedDB .
cmp
(key1, key2) -
두 값을 키로 비교합니다. key1이 key2보다 앞서면 -1, key2가 key1보다 앞서면 1, 두 키가 같으면 0을 반환합니다.
둘 중 하나라도 유효한 키가 아니면 "
DataError
"DOMException
을 throw합니다.
cmp(first, second)
메서드 단계는 다음과
같습니다:
-
a를 값을 키로 변환 단계와 first로 얻는다. 예외 발생 시 재throw한다.
-
a가 "invalid value" 또는 "invalid type"이면, throw "
DataError
"DOMException
한다. -
b를 값을 키로 변환 단계와 second로 얻는다. 예외 발생 시 재throw한다.
-
b가 "invalid value" 또는 "invalid type"이면, throw "
DataError
"DOMException
한다. -
두 키 비교를 a와 b로 실행한 결과를 반환한다.
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 = "readonly",
mode optional IDBTransactionOptions = {});
options undefined close (); [NewObject ]IDBObjectStore createObjectStore (DOMString ,
name optional IDBObjectStoreParameters = {});
options undefined deleteObjectStore (DOMString ); // Event handlers:
name attribute EventHandler onabort ;attribute EventHandler onclose ;attribute EventHandler onerror ;attribute EventHandler onversionchange ; };enum {
IDBTransactionDurability ,
"default" ,
"strict" };
"relaxed" dictionary {
IDBTransactionOptions IDBTransactionDurability = "default"; };
durability dictionary { (
IDBObjectStoreParameters DOMString or sequence <DOMString >)?=
keyPath null ;boolean =
autoIncrement false ; };
name
getter 단계는
this의 연관된 데이터베이스의 이름을 반환합니다.
참고:
name
속성은 this의 close pending flag가 true여도 이 이름을 반환합니다. 즉, 이 속성 값은 IDBDatabase
인스턴스의 생명주기 동안 항상 일정하게 유지됩니다.
version
getter 단계는
this의 버전을 반환합니다.
이 값은 데이터베이스의 버전과 동일한가요?
커넥션이 열려 있는 동안에는 연결된 데이터베이스의 버전과 동일합니다. 하지만 커넥션이 닫힘 상태가 되면, 이 속성은 이후 업그레이드 트랜잭션으로 변경된 값을 반영하지 않습니다.- connection .
objectStoreNames
-
데이터베이스 내 오브젝트 스토어의 이름들 리스트를 반환합니다.
- store = connection .
createObjectStore
(name [, options]) -
지정한 name과 options로 새로운 오브젝트 스토어를 생성하고, 새
IDBObjectStore
를 반환합니다."
InvalidStateError
"DOMException
(업그레이드 트랜잭션 내에서 호출되지 않은 경우) 예외를 발생시킵니다. - connection .
deleteObjectStore
(name) -
지정한 name의 오브젝트 스토어를 삭제합니다.
"
InvalidStateError
"DOMException
(업그레이드 트랜잭션 내에서 호출되지 않은 경우) 예외를 발생시킵니다.
objectStoreNames
getter 단계:
-
names를 list로, 이름 리스트는 오브젝트 스토어 각각에 대해, this의 object store set에서 구한다.
-
names로 정렬된 이름 리스트 생성 결과(
DOMStringList
)를 반환한다.
이 값은 데이터베이스의 오브젝트 스토어 이름들과 동일한가요?
커넥션이 열려 있는 동안에는 연결된 데이터베이스의 오브젝트 스토어 이름들과 동일합니다. 하지만 커넥션이 닫힘 상태가 되면, 이 속성은 이후 업그레이드 트랜잭션으로 변경된 값을 반영하지 않습니다.createObjectStore(name, options)
메서드 단계는 다음과 같습니다:
-
transaction을 database의 업그레이드 트랜잭션으로 하고, null이면 throw "
InvalidStateError
"DOMException
한다. -
transaction의 state가 active가 아니면 throw "
TransactionInactiveError
"DOMException
한다. -
keyPath를 options의
keyPath
가 undefined도 아니고 null도 아니면 그대로, 아니면 null로 한다. -
keyPath가 null이 아니고 유효한 key path가 아니면 throw "
SyntaxError
"DOMException
한다. -
database에 name을 가진 오브젝트 스토어가 이미 있으면 throw "
ConstraintError
"DOMException
한다. -
autoIncrement를 options의
autoIncrement
멤버로 한다. -
autoIncrement가 true이고 keyPath가 빈 문자열이거나 어떤 시퀀스(빈/비어있지 않음 포함)이면 throw "
InvalidAccessError
"DOMException
한다. -
store를 database 내 새 오브젝트 스토어로 한다. 생성된 오브젝트 스토어의 name을 name으로 설정한다. autoIncrement가 true이면, 생성된 오브젝트 스토어는 키 생성기를 사용한다. keyPath가 null이 아니면 생성된 오브젝트 스토어의 key path를 keyPath로 설정한다.
-
store와 transaction에 연관된 새 오브젝트 스토어 핸들을 반환한다.
이 메서드는 연결된 데이터베이스에 지정한 이름으로 새 오브젝트 스토어를 생성하여 반환합니다. 이 메서드는 반드시 업그레이드 트랜잭션 내에서만 호출되어야 합니다.
이 메서드는 호출된 objectStoreNames
속성을 IDBDatabase
인스턴스에서 동기적으로 수정합니다.
일부 구현체에서는 createObjectStore()
메서드가 반환된 후 오브젝트 스토어를 생성하는 작업을 큐에 추가했지만, 이후 문제가 발생할 수 있습니다(예: 새로 만든 오브젝트 스토어의 메타데이터를 비동기로 삽입하거나, 저장소 할당량(quota) 문제로
사용자에게 권한 요청이 필요한 경우). 이런 경우에도 반드시 IDBObjectStore
객체를 생성하여 반환해야 하며, 오브젝트 스토어 생성이 실패한 것으로 판단되면, 적절한 오류로 트랜잭션을 중단하는 단계를 실행해야 합니다. 예를 들어, 할당량 문제로 오브젝트 스토어 생성에 실패했다면 QuotaExceededError
를 오류로 사용해야 합니다.
deleteObjectStore(name)
메서드 단계는
다음과 같습니다:
-
transaction을 database의 업그레이드 트랜잭션으로 하고, null이면 throw "
InvalidStateError
"DOMException
한다. -
transaction의 state가 active가 아니면 throw "
TransactionInactiveError
"DOMException
한다. -
store를 database 내 오브젝트 스토어 중 name을 가진 것으로 하고, 없으면 throw "
NotFoundError
"DOMException
한다. -
store를 this의 object store set에서 제거한다.
-
store와 transaction에 연관된 오브젝트 스토어 핸들이 있으면, 해당 핸들의 index set에서 모든 항목을 제거한다.
-
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)
메서드 단계는 다음과 같습니다:
-
이 커넥션에 live 업그레이드 트랜잭션이 있으면, throw "
InvalidStateError
"DOMException
한다. -
this의 close pending flag가 true이면 throw "
InvalidStateError
"DOMException
한다. -
scope를 storeNames가 시퀀스면 고유한 문자열 집합으로, 아니면 storeNames와 동일한 하나의 문자열 집합으로 한다.
-
scope 내 어떤 문자열도 오브젝트 스토어 이름이 아니면 throw "
NotFoundError
"DOMException
한다. -
scope가 비어 있으면 throw "
InvalidAccessError
"DOMException
한다. -
transaction을 새로 생성된 트랜잭션으로 하고, 이 커넥션, mode, options의
durability
멤버, scope에 지정된 오브젝트 스토어 집합을 사용한다. -
transaction의 cleanup event loop를 현재 이벤트 루프로 설정한다.
-
transaction을 나타내는
IDBTransaction
객체를 반환한다.
durability
옵션은 이번 판에서 새로 추가되었습니다.
Chrome 82, Edge 82, Firefox 126, Safari 15에서 지원됩니다.
🚧
참고: 생성된 transaction은 생명주기 규칙을 따릅니다.
close()
메서드 단계는 다음과 같습니다:
-
데이터베이스 커넥션 닫기를 이 커넥션에 대해 실행한다.
참고:
커넥션은 모든 미완료 트랜잭션이 완료될 때까지 실제로 닫힘 상태가 되지 않습니다. 이후
close()
호출은 효과가 없습니다.
onabort
속성은 event handler IDL attribute이며, event handler event type은 abort
입니다.
onclose
속성은 event handler IDL attribute이며, event handler event type은 close
입니다.
onerror
속성은 event handler IDL attribute이며, event handler event type은 error
입니다.
onversionchange
속성은 event handler IDL attribute이며, event handler event type은 versionchange
입니다.
4.5. IDBObjectStore
인터페이스
IDBObjectStore
인터페이스는 오브젝트 스토어
핸들을 나타냅니다.
[Exposed =(Window ,Worker )]interface {
IDBObjectStore attribute DOMString name ;readonly attribute any keyPath ;readonly attribute DOMStringList indexNames ; [SameObject ]readonly attribute IDBTransaction transaction ;readonly attribute boolean autoIncrement ; [NewObject ]IDBRequest put (any ,
value optional any ); [
key NewObject ]IDBRequest add (any ,
value optional any ); [
key NewObject ]IDBRequest delete (any ); [
query NewObject ]IDBRequest clear (); [NewObject ]IDBRequest get (any ); [
query NewObject ]IDBRequest getKey (any ); [
query NewObject ]IDBRequest getAll (optional any ,
queryOrOptions optional [EnforceRange ]unsigned long ); [
count NewObject ]IDBRequest getAllKeys (optional any ,
queryOrOptions optional [EnforceRange ]unsigned long ); [
count NewObject ]IDBRequest getAllRecords (optional IDBGetAllOptions = {}); [
options NewObject ]IDBRequest count (optional any ); [
query NewObject ]IDBRequest openCursor (optional any ,
query optional IDBCursorDirection = "next"); [
direction NewObject ]IDBRequest openKeyCursor (optional any ,
query optional IDBCursorDirection = "next");
direction 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 = "next"; };
direction
- 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 단계는 다음과 같습니다:
-
name을 지정된 값으로 설정합니다.
-
store가 삭제된 경우, throw "
InvalidStateError
"DOMException
을 발생시킵니다. -
transaction이 업그레이드 트랜잭션이 아니면, throw "
InvalidStateError
"DOMException
을 발생시킵니다. -
transaction의 상태가 active가 아니면, throw "
TransactionInactiveError
"DOMException
을 발생시킵니다. -
store의 이름이 name과 같으면 이 단계를 종료합니다.
-
name으로 오브젝트 스토어가 이미 존재하면, store의 데이터베이스에서 throw "
ConstraintError
"DOMException
을 발생시킵니다. -
store의 이름을 name으로 설정합니다.
keyPath
getter 단계는
this의 오브젝트 스토어의 키 경로를 반환하거나,
없으면 null을 반환합니다. 키 경로는 DOMString
(문자열인 경우) 또는
sequence<
(문자열 목록인 경우)로 변환됩니다. 자세한 내용은
[WEBIDL]을 참고하세요.
DOMString
>
NOTE:
반환된 값은 오브젝트 스토어가 생성될 때 사용된 인스턴스와 동일하지 않습니다.
단, 해당 속성이 객체(특히 Array
)를
반환할 경우,
매번 동일한 객체 인스턴스를 반환합니다. 객체의 속성을 변경해도 오브젝트 스토어에는 영향을 주지 않습니다.
indexNames
getter 단계는 다음과 같습니다:
-
names를 리스트로 설정합니다. 이 리스트는 이름들의 모음이며, 인덱스들이 this의 index set에 포함되어 있습니다.
-
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]) - request = store .
-
지정된 value와 key로 레코드를 store에 추가하거나 갱신합니다.
store가 인라인 키를 사용할 때 key가 지정되면 "
DataError
"DOMException
예외가 발생합니다.put()
를 사용하면 기존 레코드가 키 기준으로 대체됩니다.add()
를 사용하면, 레코드가 이미 해당 키로 존재할 경우 request는 실패하며, request의error
속성이 "ConstraintError
"DOMException
으로 설정됩니다. - request = store .
delete
(query) -
store에서 지정된 키 또는 키 범위에 해당하는 레코드를 삭제합니다.
성공 시 request의
result
값은undefined
가 됩니다. - request = store .
clear
() -
store의 모든 레코드를 삭제합니다.
성공 시 request의
result
값은undefined
가 됩니다.
put(value, key)
메서드 단계는
add or put을 this, value,
key 그리고 no-overwrite flag를 false로 하여 실행한 결과를 반환하는 것입니다.
add(value, key)
메서드 단계는
add or put을 this, value,
key 그리고 no-overwrite flag를 true로 하여 실행한 결과를 반환하는 것입니다.
add or put을 handle, value, key, no-overwrite flag와 함께 실행하는 단계는 다음과 같습니다:
-
transaction을 handle의 트랜잭션으로 설정합니다.
-
store를 handle의 오브젝트 스토어로 설정합니다.
-
store가 삭제된 경우, throw "
InvalidStateError
"DOMException
을 발생시킵니다. -
transaction의 상태가 active가 아니면, throw "
TransactionInactiveError
"DOMException
을 발생시킵니다. -
transaction이 읽기 전용 트랜잭션이면, throw "
ReadOnlyError
"DOMException
을 발생시킵니다. -
store가 인라인 키를 사용하면서 key가 주어진 경우, throw "
DataError
"DOMException
을 발생시킵니다. -
store가 아웃라인 키를 사용하고 키 생성기가 없으며 key가 주어지지 않았다면, throw "
DataError
"DOMException
을 발생시킵니다. -
key가 주어진 경우:
-
r을 값을 키로 변환 알고리듬을 key로 실행하여 얻습니다. 예외가 발생하면 다시 throw 합니다.
-
r이 "invalid value" 또는 "invalid type"이면, throw "
DataError
"DOMException
을 발생시킵니다. -
key를 r로 설정합니다.
-
-
targetRealm을 user-agent가 정의하는 Realm으로 설정합니다.
-
clone을 transaction 중 targetRealm에서 value의 복제로 설정합니다. 예외가 발생하면 다시 throw 합니다.
왜 값을 복제하나요?
값은 저장될 때 직렬화됩니다. 여기서 복제본으로 다루는 것은 이 명세의 다른 알고리듬들이 ECMAScript 값으로 다루도록 하기 위함입니다. 단, 구현체는 행동 차이가 관찰되지 않는 한 최적화할 수 있습니다. -
store가 인라인 키를 사용하면:
-
kpk를 키 경로를 이용해 값에서 키 추출 알고리듬을 clone과 store의 키 경로로 실행하여 얻습니다. 예외가 발생하면 다시 throw 합니다.
-
kpk가 invalid이면, throw "
DataError
"DOMException
을 발생시킵니다. -
kpk가 실패가 아니면 key를 kpk로 설정합니다.
-
그 외(kpk가 실패):
-
store가 키 생성기가 없으면, throw "
DataError
"DOMException
을 발생시킵니다. -
키가 값에 주입될 수 있는지 확인 알고리듬을 clone과 store의 키 경로로 실행하여 false가 나오면, throw "
DataError
"DOMException
을 발생시킵니다.
-
-
-
operation을 오브젝트 스토어에 레코드 저장 알고리듬을 store, clone, key, no-overwrite flag로 실행하는 알고리듬으로 설정합니다.
-
handle과 operation으로 요청을 비동기적으로 실행 알고리듬을 실행한 결과(
IDBRequest
)를 반환합니다.
delete(query)
메서드 단계는 다음과 같습니다:
-
store가 삭제된 경우, throw "
InvalidStateError
"DOMException
을 발생시킵니다. -
transaction의 상태가 active가 아니면, throw "
TransactionInactiveError
"DOMException
을 발생시킵니다. -
transaction이 읽기 전용 트랜잭션이면, throw "
ReadOnlyError
"DOMException
을 발생시킵니다. -
range를 값을 키 범위로 변환 알고리듬을 query와 true로 실행한 결과로 설정합니다. 예외가 발생하면 다시 throw 합니다.
-
operation을 오브젝트 스토어에서 레코드 삭제 알고리듬을 store와 range로 실행하는 알고리듬으로 설정합니다.
-
this와 operation으로 요청을 비동기적으로 실행 알고리듬을 실행한 결과(
IDBRequest
)를 반환합니다.
NOTE:
query 매개변수는 키 또는 키 범위(IDBKeyRange
)가
될 수 있으며,
삭제 대상 레코드를
식별합니다.
참고: 키 또는 키 범위를 받는 다른 메서드들과 달리, 이 메서드는 null을 키로 지정할 수 없습니다. 이는 작은 버그로 전체 오브젝트 스토어가 삭제되는 위험을 줄이기 위함입니다.
clear()
메서드 단계는 다음과 같습니다:
-
store가 삭제된 경우, throw "
InvalidStateError
"DOMException
을 발생시킵니다. -
transaction의 상태가 active가 아니면, throw "
TransactionInactiveError
"DOMException
을 발생시킵니다. -
transaction이 읽기 전용 트랜잭션이면, throw "
ReadOnlyError
"DOMException
을 발생시킵니다. -
operation을 오브젝트 스토어 비우기 알고리듬을 store로 실행하는 알고리듬으로 설정합니다.
-
this와 operation으로 요청을 비동기적으로 실행 알고리듬을 실행한 결과(
IDBRequest
)를 반환합니다.
TransactionInactiveError
"
DOMException
예외가 발생합니다.
- request = store .
get
(query) - request = store .
getKey
(query) - request = store .
getAll
(query [, count])- request = store .
getAll
({query, count, direction}) - request = store .
-
지정된 키 또는 키 범위에 맞는 레코드의 값들을 가져옵니다(옵션 count까지). direction 옵션을 "
next
"로 설정하면 처음 count개의 값, "prev
"로 설정하면 마지막 count개의 값을 반환합니다. - request = store .
getAllKeys
(query [, count])- request = store .
getAllKeys
({query, count, direction}) - request = store .
-
지정된 키 또는 키 범위에 맞는 레코드의 키들을 가져옵니다(옵션 count까지). direction 옵션을 "
next
"로 설정하면 처음 count개의 키, "prev
"로 설정하면 마지막 count개의 키를 반환합니다. - request = store .
getAllRecords
({query, count, direction}) -
query 옵션은 매칭할 키 또는 키 범위를 지정합니다. count 옵션은 일치하는 레코드 수를 제한합니다. direction 옵션을 "
next
"로 설정하면 처음 count개의 레코드, "prev
"로 설정하면 마지막 count개의 레코드를 반환합니다. - request = store .
count
(query) -
지정된 키 또는 키 범위에 맞는 레코드의 개수를 가져옵니다.
성공 시 request의
result
값은 개수입니다.
get(query)
메서드 단계는 다음과 같습니다:
-
store가 삭제된 경우, throw "
InvalidStateError
"DOMException
을 발생시킵니다. -
transaction의 상태가 active가 아니면, throw "
TransactionInactiveError
"DOMException
을 발생시킵니다. -
range를 값을 키 범위로 변환 알고리듬을 query와 true로 실행한 결과로 설정합니다. 예외가 발생하면 다시 throw 합니다.
-
operation을 오브젝트 스토어에서 값 가져오기 알고리듬을 현재 Realm 레코드, store, range로 실행하는 알고리듬으로 설정합니다.
-
this와 operation으로 요청을 비동기적으로 실행 알고리듬을 실행한 결과(
IDBRequest
)를 반환합니다.
참고:
query 매개변수는 키 또는 키 범위(IDBKeyRange
)가
될 수 있으며,
가져올 레코드 값을
식별합니다. 범위가 지정된 경우, 해당 범위에 존재하는 첫 번째 값을 가져옵니다.
참고:
이 메서드는 주어진 키의 레코드가 존재하지 않을 때와, 레코드가 존재하지만 값이 undefined
일 때 동일한 결과를 반환합니다.
두 상황을 구분해야 한다면, 같은 키로 openCursor()
를 사용할 수 있습니다. 이 경우 레코드가 있으면 값이 undefined
인 커서가 반환되며, 레코드가 없으면 커서가 반환되지 않습니다.
getKey(query)
메서드 단계는 다음과 같습니다:
-
store가 삭제된 경우, throw "
InvalidStateError
"DOMException
을 발생시킵니다. -
transaction의 상태가 active가 아니면, throw "
TransactionInactiveError
"DOMException
을 발생시킵니다. -
range를 값을 키 범위로 변환 알고리듬을 query와 true로 실행한 결과로 설정합니다. 예외가 발생하면 다시 throw 합니다.
-
operation을 오브젝트 스토어에서 키 가져오기 알고리듬을 store와 range로 실행하는 알고리듬으로 설정합니다.
-
this와 operation으로 요청을 비동기적으로 실행 알고리듬을 실행한 결과(
IDBRequest
)를 반환합니다.
참고:
query 매개변수는 키 또는 키 범위(IDBKeyRange
)가
될 수 있으며,
가져올 레코드의 키를
식별합니다. 범위가 지정된 경우, 해당 범위에 존재하는 첫 번째 키를 가져옵니다.
getAll(queryOrOptions, count)
메서드 단계는 다음과 같습니다:
-
여러 항목을 가져오는 요청 생성 알고리듬을 현재 Realm 레코드, this, "value", queryOrOptions, count(있으면)로 실행한 결과를 반환합니다. 예외가 발생하면 다시 throw 합니다.
getAllKeys(queryOrOptions, count)
메서드 단계는 다음과 같습니다:
-
여러 항목을 가져오는 요청 생성 알고리듬을 현재 Realm 레코드, this, "key", queryOrOptions, count(있으면)로 실행한 결과를 반환합니다. 예외가 발생하면 다시 throw 합니다.
getAllRecords(options)
메서드 단계는
다음과 같습니다:
-
여러 항목을 가져오는 요청 생성 알고리듬을 현재 Realm 레코드, this, "record", options로 실행한 결과를 반환합니다. 예외가 발생하면 다시 throw 합니다.
count(query)
메서드 단계는 다음과 같습니다:
-
store가 삭제된 경우, throw "
InvalidStateError
"DOMException
을 발생시킵니다. -
transaction의 상태가 active가 아니면, throw "
TransactionInactiveError
"DOMException
을 발생시킵니다. -
range를 값을 키 범위로 변환 알고리듬을 query로 실행한 결과로 설정합니다. 예외가 발생하면 다시 throw 합니다.
-
operation을 범위 내 레코드 개수 세기 알고리듬을 store와 range로 실행하는 알고리듬으로 설정합니다.
-
this와 operation으로 요청을 비동기적으로 실행 알고리듬을 실행한 결과(
IDBRequest
)를 반환합니다.
참고:
query 매개변수는 키 또는 키 범위(IDBKeyRange
)가
될 수 있으며,
개수를 셀 레코드를
식별합니다. null 또는 생략된 경우 제한 없는 키 범위가 사용됩니다.
TransactionInactiveError
"
DOMException
예외가 발생합니다.
- request = store .
openCursor
([query [, direction = "next"]]) -
query에 맞는 레코드들에 대해 direction 순서로 커서를 엽니다. query가 null이면 store의 모든 레코드가 매칭됩니다.
성공 시 request의
result
값은IDBCursorWithValue
이며, 첫 번째로 매칭된 레코드를 가리키거나, 매칭되는 레코드가 없으면 null입니다. - request = store .
openKeyCursor
([query [, direction = "next"]]) -
query에 맞는 레코드들에 대해 direction 순서로 커서를 엽니다. key only flag가 true로 설정되어 있습니다. query가 null이면 store의 모든 레코드가 매칭됩니다.
성공 시 request의
result
값은IDBCursor
이며, 첫 번째로 매칭된 레코드를 가리키거나, 매칭되는 레코드가 없으면 null입니다.
openCursor(query, direction)
메서드 단계는 다음과 같습니다:
-
store가 삭제된 경우, throw "
InvalidStateError
"DOMException
을 발생시킵니다. -
transaction의 상태가 active가 아니면, throw "
TransactionInactiveError
"DOMException
을 발생시킵니다. -
range를 값을 키 범위로 변환 알고리듬을 query로 실행한 결과로 설정합니다. 예외가 발생하면 다시 throw 합니다.
-
cursor를 새로운 커서로 생성하며, source handle은 this로, position은 undefined로, direction은 direction으로, got value flag는 false로, key와 value는 undefined로, range는 range로, key only flag는 false로 설정합니다.
-
operation을 커서를 반복 알고리듬을 현재 Realm 레코드, cursor로 실행하는 알고리듬으로 설정합니다.
-
request를 요청을 비동기적으로 실행 알고리듬을 this, operation으로 실행한 결과로 설정합니다.
-
cursor의 request를 request로 설정합니다.
-
request를 반환합니다.
참고:
query 매개변수는 키 또는 키 범위(IDBKeyRange
)가
될 수 있으며,
커서의 범위로 사용됩니다.
null 또는 생략된 경우 제한
없는 키 범위가 사용됩니다.
openKeyCursor(query, direction)
메서드 단계는 다음과 같습니다:
-
store가 삭제된 경우, throw "
InvalidStateError
"DOMException
을 발생시킵니다. -
transaction의 상태가 active가 아니면, throw "
TransactionInactiveError
"DOMException
을 발생시킵니다. -
range를 값을 키 범위로 변환 알고리듬을 query로 실행한 결과로 설정합니다. 예외가 발생하면 다시 throw 합니다.
-
cursor를 새로운 커서로 생성하며, source handle은 this로, position은 undefined로, direction은 direction으로, got value flag는 false로, key와 value는 undefined로, range는 range로, key only flag는 true로 설정합니다.
-
operation을 커서를 반복 알고리듬을 현재 Realm 레코드, cursor로 실행하는 알고리듬으로 설정합니다.
-
request를 요청을 비동기적으로 실행 알고리듬을 this, operation으로 실행한 결과로 설정합니다.
-
cursor의 request를 request로 설정합니다.
-
request를 반환합니다.
참고:
query 매개변수는 키 또는 키 범위(IDBKeyRange
)가
될 수 있으며,
커서의 범위로 사용됩니다. null
또는 생략된 경우 제한 없는 키
범위가 사용됩니다.
- index = store . index(name)
- index = store .
createIndex
(name, keyPath [, options]) -
store에 주어진 name, keyPath, options으로 새로운 인덱스를 생성하고 새로운
IDBIndex
를 반환합니다. 만약 keyPath와 options가 store에 이미 있는 데이터와 맞지 않는 제약 조건을 정의하면 업그레이드 트랜잭션이 "ConstraintError
"DOMException
과 함께 중단(abort)됩니다.업그레이드 트랜잭션 내에서 호출하지 않으면 "
InvalidStateError
"DOMException
예외가 발생합니다. - store .
deleteIndex
(name) -
store에서 주어진 name의 인덱스를 삭제합니다.
업그레이드 트랜잭션 내에서 호출하지 않으면 "
InvalidStateError
"DOMException
예외가 발생합니다.
createIndex(name, keyPath, options)
메서드 단계는 다음과 같습니다:
-
transaction이 업그레이드 트랜잭션이 아니면, throw "
InvalidStateError
"DOMException
을 발생시킵니다. -
store가 삭제된 경우, throw "
InvalidStateError
"DOMException
을 발생시킵니다. -
transaction의 상태가 active가 아니면, throw "
TransactionInactiveError
"DOMException
을 발생시킵니다. -
store에 name이라는 이름의 인덱스가 이미 있으면, throw "
ConstraintError
"DOMException
을 발생시킵니다. -
keyPath가 유효한 키 경로가 아니면, throw "
SyntaxError
"DOMException
을 발생시킵니다. -
unique를 options의
unique
멤버로 설정합니다. -
multiEntry를 options의
multiEntry
멤버로 설정합니다. -
keyPath가 시퀀스이고 multiEntry가 true이면, throw "
InvalidAccessError
"DOMException
을 발생시킵니다. -
index를 store에 새로운 인덱스로 생성합니다. index의 이름을 name으로, 키 경로를 keyPath로, unique flag를 unique로, multiEntry flag를 multiEntry로 설정합니다.
-
index와 this에 연결된 새로운 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)
메서드 단계는 다음과 같습니다:
-
store가 삭제된 경우, throw "
InvalidStateError
"DOMException
을 발생시킵니다. -
transaction의 상태가 finished이면, throw "
InvalidStateError
"DOMException
을 발생시킵니다. -
index를 index set에서 name 이름의 인덱스로 설정합니다. 없으면 throw "
NotFoundError
"DOMException
을 발생시킵니다. -
index와 this에 연결된 index handle을 반환합니다.
참고:
동일한 IDBObjectStore
인스턴스에서 같은 이름으로 이 메서드를 여러 번 호출하면 같은 IDBIndex
인스턴스를 반환합니다.
참고:
반환된 IDBIndex
인스턴스는 해당
IDBObjectStore
인스턴스에만 특화되어 있습니다. 다른 IDBObjectStore
인스턴스에서 같은 이름으로 호출하면 다른 IDBIndex
인스턴스를 반환합니다.
deleteIndex(name)
메서드 단계는 다음과
같습니다:
-
transaction이 업그레이드 트랜잭션이 아니면, throw "
InvalidStateError
"DOMException
을 발생시킵니다. -
store가 삭제된 경우, throw "
InvalidStateError
"DOMException
을 발생시킵니다. -
transaction의 상태가 active가 아니면, throw "
TransactionInactiveError
"DOMException
을 발생시킵니다. -
index를 store에서 name 이름의 인덱스로 설정합니다. 없으면 throw "
NotFoundError
"DOMException
을 발생시킵니다. -
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 = "next"); [
direction NewObject ]IDBRequest openKeyCursor (optional any ,
query optional IDBCursorDirection = "next"); };
direction
- 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 단계는 다음과 같습니다:
-
name에 the given value를 할당합니다.
-
transaction에 this의 transaction을 할당합니다.
-
transaction이 upgrade transaction이 아니면, throw "
InvalidStateError
"DOMException
오류를 발생시킵니다. -
transaction의 state가 active가 아니면, throw "
TransactionInactiveError
"DOMException
오류를 발생시킵니다. -
index 또는 index의 object store가 삭제된 경우, throw "
InvalidStateError
"DOMException
오류를 발생시킵니다. -
index의 name이 name과 같으면, 이 단계를 종료합니다.
-
name으로 index named가 이미 index의 object store에 존재하면, throw "
ConstraintError
"DOMException
오류를 발생시킵니다. -
index의 name을 name으로 설정합니다.
objectStore
getter 단계는
this의 object store handle을 반환합니다.
keyPath
getter 단계는
this의 index의
key path를
반환합니다.
key path는
DOMString
(문자열일 경우) 또는
sequence<
(문자열 리스트일 경우)로 변환됩니다. 자세한 내용은 [WEBIDL]를 참고하세요.
DOMString
>
참고:
반환된 값은 index가 생성될 때 사용된 인스턴스와
동일하지 않습니다.
하지만 이 속성이 객체(특히 Array
)를
반환하는 경우,
검사할 때마다 동일한 객체 인스턴스를 반환합니다. 객체의 프로퍼티를 변경해도 index에는 영향을 주지 않습니다.
multiEntry
getter 단계는
this의 index의 multiEntry
flag를 반환합니다.
unique
getter 단계는
this의 index의 unique flag를 반환합니다.
TransactionInactiveError
"
DOMException
오류를 발생시킵니다.
transaction이 active가 아닐 때 호출하면
발생합니다.
- request = index .
get
(query) -
주어진 key 또는 key range와 일치하는 첫 번째 record의 value를 가져옵니다.
성공하면 request의
result
값은 value가 되고, 일치하는 record가 없으면undefined
입니다. - request = index .
getKey
(query) -
주어진 key 또는 key range와 일치하는 첫 번째 record의 key를 가져옵니다.
성공하면 request의
result
값은 key가 되고, 일치하는 record가 없으면undefined
입니다. - request = index .
getAll
(query [, count])- request = index .
getAll
({query, count, direction}) - request = index .
-
주어진 key 또는 key range와 일치하는 records의 values를 가져옵니다. (count가 있으면 최대 count개까지) direction 옵션을 "
next
" 로 설정하면 첫 count개의 값을, "prev
" 로 설정하면 마지막 count개의 값을 반환합니다. direction 옵션을 "nextunique
" 또는 "prevunique
" 로 설정하면 중복된 인덱스 키가 있는 레코드는 첫 번째 레코드만 가져오고 이후 중복은 제외합니다. - request = index .
getAllKeys
(query [, count])- request = index .
getAllKeys
({query, count, direction}) - request = index .
-
주어진 key 또는 key range와 일치하는 records의 keys를 가져옵니다. (count가 있으면 최대 count개까지) direction 옵션을 "
next
" 로 설정하면 첫 count개의 키를, "prev
" 로 설정하면 마지막 count개의 키를 반환합니다. direction 옵션을 "nextunique
" 또는 "prevunique
" 로 설정하면 중복된 인덱스 키가 있는 레코드는 첫 번째 레코드만 가져오고 이후 중복은 제외합니다. - request = index .
getAllRecords
({query, count, direction}) -
records의 keys, values, 그리고 인덱스 keys를 가져옵니다.
query 옵션은 일치시킬 key 또는 key range를 지정합니다. count 옵션은 일치시키는 레코드의 수를 제한합니다. direction 옵션을 "
next
" 로 설정하면 첫 count개의 레코드를, "prev
" 로 설정하면 마지막 count개의 레코드를 반환합니다. direction 옵션을 "nextunique
" 또는 "prevunique
" 로 설정하면 중복된 인덱스 키가 있는 레코드는 첫 번째 레코드만 가져오고 이후 중복은 제외합니다.성공하면 request의
result
값은Array
형태이며, 각 멤버는IDBRecord
입니다.IDBRecord의 key
를 사용하여 해당 레코드의 인덱스 key를 얻을 수 있습니다.IDBRecord의 primaryKey
를 사용하여 해당 레코드의 key를 얻을 수 있습니다. - request = index .
count
(query) -
주어진 key 또는 key range와 일치하는 records의 개수를 가져옵니다.
성공하면 request의
result
값은 해당 개수(count)입니다.
get(query)
메서드 단계는 다음과 같습니다:
-
transaction에 this의 transaction을 할당합니다.
-
index 또는 index의 object store가 삭제된 경우, throw "
InvalidStateError
"DOMException
오류를 발생시킵니다. -
transaction의 state가 active가 아니면, throw "
TransactionInactiveError
"DOMException
오류를 발생시킵니다. -
range에 convert a value to a key range의 결과를 query와 true로 호출하여 할당합니다. 예외가 발생하면 재throw합니다.
-
operation에 retrieve a referenced value from an index를 the current Realm record, index, range와 함께 실행하는 알고리즘을 할당합니다.
-
asynchronously execute a request를 this와 operation을 사용하여 실행한 결과(
IDBRequest
)를 반환합니다.
참고:
query 파라미터는 key
또는 key range(IDBKeyRange
)일
수 있으며,
가져올 referenced value를 식별합니다. 범위를 지정하면, 해당 범위 내에서 첫 번째로 존재하는
레코드를 가져옵니다.
참고:
주어진 key에 해당하는 레코드가 없을 때와, 해당 key의 레코드 값이 undefined
인 경우 결과는 동일합니다.
두 상황을 구분하려면 동일한 key로 openCursor()
를 사용할 수 있습니다. 이 경우 레코드가 존재하면 값이 undefined
인 커서를 반환하며, 레코드가 없으면 커서 자체가 반환되지 않습니다.
getKey(query)
메서드 단계는 다음과 같습니다:
-
transaction에 this의 transaction을 할당합니다.
-
index 또는 index의 object store가 삭제된 경우, throw "
InvalidStateError
"DOMException
오류를 발생시킵니다. -
transaction의 state가 active가 아니면, throw "
TransactionInactiveError
"DOMException
오류를 발생시킵니다. -
range에 convert a value to a key range의 결과를 query와 true로 호출하여 할당합니다. 예외가 발생하면 재throw합니다.
-
operation에 retrieve a value from an index를 index와 range와 함께 실행하는 알고리즘을 할당합니다.
-
asynchronously execute a request를 this와 operation을 사용하여 실행한 결과(
IDBRequest
)를 반환합니다.
참고:
query 파라미터는 key
또는 key range(IDBKeyRange
)일
수 있으며,
가져올 record의
key를 식별합니다.
범위를 지정하면, 해당 범위 내에서 첫 번째로 존재하는 key를 가져옵니다.
getAll(queryOrOptions, count)
메서드 단계는 다음과 같습니다:
-
여러 항목을 검색하는 요청 생성을 현재 Realm 레코드, this, "value", queryOrOptions, 그리고 count가 주어졌다면 count와 함께 실행한 결과를 반환합니다. 예외가 발생하면 다시 throw합니다.
getAllKeys(queryOrOptions, count)
메서드 단계는 다음과 같습니다:
-
여러 항목을 검색하는 요청 생성을 현재 Realm 레코드, this, "key", queryOrOptions, 그리고 count가 주어졌다면 count와 함께 실행한 결과를 반환합니다. 예외가 발생하면 다시 throw합니다.
getAllRecords(options)
메서드 단계는 다음과
같습니다:
-
여러 항목을 검색하는 요청 생성을 현재 Realm 레코드, this, "record", 그리고 options와 함께 실행한 결과를 반환합니다. 예외가 발생하면 다시 throw합니다.
count(query)
메서드 단계는 다음과 같습니다:
-
transaction에 this의 transaction을 할당합니다.
-
index 또는 index의 object store가 삭제된 경우, throw "
InvalidStateError
"DOMException
오류를 발생시킵니다. -
transaction의 state가 active가 아니면, throw "
TransactionInactiveError
"DOMException
오류를 발생시킵니다. -
range에 값을 키 범위로 변환의 결과를 query로 호출하여 할당합니다. 예외가 발생하면 다시 throw합니다.
-
operation에 범위 내 레코드 개수 세기를 index와 range로 실행하는 알고리즘을 할당합니다.
-
비동기적으로 요청 실행을 this와 operation을 사용하여 실행한 결과(
IDBRequest
)를 반환합니다.
참고:
query 파라미터는 key
또는 key range(IDBKeyRange
)일
수 있으며,
카운트할 records를 식별합니다.
null이거나 지정되지 않으면,
제한 없는 키 범위가
사용됩니다.
TransactionInactiveError
"
DOMException
을
던집니다.
- request = index .
openCursor
([query [, direction = "next"]]) -
query에 일치하는 레코드들을 direction 순서로 커서로 엽니다. query가 null이면, index의 모든 레코드가 일치합니다.
성공하면 request의
result
는IDBCursorWithValue
이거나, 일치하는 레코드가 없으면 null입니다. - request = index .
openKeyCursor
([query [, direction = "next"]]) -
키 전용 플래그가 true로 설정된 커서를 query에 일치하는 레코드들에 대해 direction 순서로 엽니다. query가 null이면, index의 모든 레코드가 일치합니다.
성공하면 request의
result
는IDBCursor
이거나, 일치하는 레코드가 없으면 null입니다.
openCursor(query, direction)
메서드 단계는 다음과 같습니다:
-
transaction을 this의 transaction으로 설정한다.
-
index 또는 index의 object store가 삭제된 경우, throw "
InvalidStateError
"DOMException
을 발생시킨다. -
transaction의 state가 active가 아니면, throw "
TransactionInactiveError
"DOMException
을 발생시킨다. -
range를 값을 키 범위로 변환하기의 결과로 query를 사용하여 설정한다. 예외가 발생하면 다시 던진다.
-
cursor를 새로운 cursor로 생성하고, source handle은 this로, position은 undefined로, direction은 direction으로, got value flag는 false로, key와 value는 undefined로, range는 range로, key only flag는 false로 설정한다.
-
operation을 커서를 반복하기를 현재 Realm record와 cursor로 실행하는 알고리즘으로 설정한다.
-
request를 요청을 비동기로 실행하기를 this와 operation으로 실행한 결과로 설정한다.
-
cursor의 request를 request로 설정한다.
-
request를 반환한다.
NOTE:
query 매개변수는 key
또는 key range (IDBKeyRange
)
를 cursor의 range로 사용할 수 있습니다. null이거나 지정되지 않은 경우, 제한 없는 키 범위가
사용됩니다.
openKeyCursor(query, direction)
메서드 단계는 다음과 같습니다:
-
transaction을 this의 transaction으로 설정한다.
-
index 또는 index의 object store가 삭제된 경우, throw "
InvalidStateError
"DOMException
을 발생시킨다. -
transaction의 state가 active가 아니면, throw "
TransactionInactiveError
"DOMException
을 발생시킨다. -
range를 값을 키 범위로 변환하기의 결과로 query를 사용하여 설정한다. 예외가 발생하면 다시 던진다.
-
cursor를 새로운 cursor로 생성하고, source handle은 this로, position은 undefined로, direction은 direction으로, got value flag는 false로, key와 value는 undefined로, range는 range로, key only flag는 true로 설정한다.
-
operation을 커서를 반복하기를 현재 Realm record와 cursor로 실행하는 알고리즘으로 설정한다.
-
request를 요청을 비동기로 실행하기를 this와 operation으로 실행한 결과로 설정한다.
-
cursor의 request를 request로 설정한다.
-
request를 반환한다.
NOTE:
query 매개변수는 key
또는 key range (IDBKeyRange
)
를 cursor의 range로 사용할 수 있습니다. null이거나 지정되지 않은 경우, 제한 없는 키 범위가
사용됩니다.
4.7. IDBKeyRange
인터페이스
IDBKeyRange
인터페이스는
키 범위를 나타냅니다.
[Exposed =(Window ,Worker )]interface {
IDBKeyRange readonly attribute any lower ;readonly attribute any upper ;readonly attribute boolean lowerOpen ;readonly attribute boolean upperOpen ; // Static construction methods: [NewObject ]static IDBKeyRange only (any ); [
value NewObject ]static IDBKeyRange lowerBound (any ,
lower optional boolean =
open false ); [NewObject ]static IDBKeyRange upperBound (any ,
upper optional boolean =
open false ); [NewObject ]static IDBKeyRange bound (any ,
lower any ,
upper optional boolean =
lowerOpen false ,optional boolean =
upperOpen false );boolean includes (any ); };
key
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)
메서드 단계는 다음과 같습니다:
-
key를 값을 키로 변환하기의 결과로 value를 사용하여 얻는다. 예외가 발생하면 다시 던진다.
-
key가 "invalid value" 또는 "invalid type"이면, throw "
DataError
"DOMException
을 발생시킨다. -
새로운 키 범위를 해당 키만 포함하도록 생성하여 반환한다. key.
lowerBound(lower, open)
메서드 단계는 다음과 같습니다:
-
lowerKey를 값을 키로 변환하기의 결과로 lower를 사용하여 얻는다. 예외가 발생하면 다시 던진다.
-
lowerKey가 유효하지 않으면, throw "
DataError
"DOMException
을 발생시킨다. -
새로운 키 범위를 생성하여 하한을 lowerKey로, 하한 개방 플래그를 open으로, 상한을 null로, 상한 개방 플래그를 true로 설정하여 반환한다.
upperBound(upper, open)
메서드 단계는 다음과 같습니다:
-
upperKey를 값을 키로 변환하기의 결과로 upper를 사용하여 얻는다. 예외가 발생하면 다시 던진다.
-
upperKey가 "invalid value" 또는 "invalid type"이면, throw "
DataError
"DOMException
을 발생시킨다. -
새로운 키 범위를 생성하여 하한을 null로, 하한 개방 플래그를 true로, 상한을 upperKey로, 상한 개방 플래그를 open으로 설정하여 반환한다.
bound(lower, upper, lowerOpen, upperOpen)
메서드 단계는 다음과 같습니다:
-
lowerKey를 값을 키로 변환하기의 결과로 lower를 사용하여 얻는다. 예외가 발생하면 다시 던진다.
-
lowerKey가 "invalid value" 또는 "invalid type"이면, throw "
DataError
"DOMException
을 발생시킨다. -
upperKey를 값을 키로 변환하기의 결과로 upper를 사용하여 얻는다. 예외가 발생하면 다시 던진다.
-
upperKey가 "invalid value" 또는 "invalid type"이면, throw "
DataError
"DOMException
을 발생시킨다. -
lowerKey가 upperKey보다 크면, throw "
DataError
"DOMException
을 발생시킨다. -
새로운 키 범위를 생성하여 하한을 lowerKey로, 하한 개방 플래그를 lowerOpen으로, 상한을 upperKey로, 상한 개방 플래그를 upperOpen으로 설정하여 반환한다.
- range .
includes
(key) -
key가 해당 범위에 포함되어 있으면 true를, 그렇지 않으면 false를 반환합니다.
includes(key)
메서드 단계는 다음과 같습니다:
-
k를 값을 키로 변환하기의 결과로 key를 사용하여 얻는다. 예외가 발생하면 다시 던진다.
-
k가 "invalid value" 또는 "invalid type"이면, throw "
DataError
"DOMException
을 발생시킨다. -
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 .
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) -
커서를 범위 내 key 및 primaryKey와 일치하거나 그 이후의 레코드로 이동시킵니다. 소스가 인덱스가 아닌 경우에는 "
InvalidAccessError
"DOMException
이 발생합니다.
advance(count)
메서드 단계는 다음과 같습니다:
-
transaction의 상태가 활성이 아니면, throw "
TransactionInactiveError
"DOMException
을 발생시킨다. -
this의 소스 또는 실효 오브젝트 스토어가 삭제된 경우, throw "
InvalidStateError
"DOMException
을 발생시킨다. -
this의 got value flag가 false이면(커서가 반복 중이거나 끝까지 반복된 경우), throw "
InvalidStateError
"DOMException
을 발생시킨다. -
this의 got value flag를 false로 설정한다.
-
request의 processed flag를 false로 설정한다.
-
request의 done flag를 false로 설정한다.
-
operation을 커서 반복하기 알고리즘으로, 현재 Realm record, this, count로 실행한다.
-
요청 비동기 실행하기를 this의 소스 핸들, operation, request로 실행한다.
NOTE:
새 커서 데이터가 로드되기 전 이 메서드를 두 번 이상 호출하면(예: 같은 onsuccess 핸들러 내에서 advance()
를 두 번 호출하면) 두 번째 호출 시 "InvalidStateError
"
DOMException
이 발생합니다. 이는 커서의 got value flag가 false로 설정되었기 때문입니다.
continue(key)
메서드 단계는 다음과 같습니다:
-
transaction의 상태가 활성이 아니면, throw "
TransactionInactiveError
"DOMException
을 발생시킨다. -
this의 소스 또는 실효 오브젝트 스토어가 삭제된 경우, throw "
InvalidStateError
"DOMException
을 발생시킨다. -
this의 got value flag가 false이면(커서가 반복 중이거나 끝까지 반복된 경우), throw "
InvalidStateError
"DOMException
을 발생시킨다. -
key가 주어지면:
-
r을 값을 키로 변환하기의 결과로 key를 사용하여 얻는다. 예외가 발생하면 다시 던진다.
-
r이 "invalid value" 또는 "invalid type"이면, throw "
DataError
"DOMException
을 발생시킨다. -
key를 r로 설정한다.
-
key가 보다 작거나 같으면 this의 포지션이고, this의 방향이 "
next
" 또는 "nextunique
"이면, throw "DataError
"DOMException
을 발생시킨다. -
key가 보다 크거나 같으면 this의 포지션이고, this의 방향이 "
prev
" 또는 "prevunique
"이면, throw "DataError
"DOMException
을 발생시킨다.
-
-
this의 got value flag를 false로 설정한다.
-
request의 processed flag를 false로 설정한다.
-
request의 done flag를 false로 설정한다.
-
operation을 커서 반복하기 알고리즘으로, 현재 Realm record, this, key(있으면)로 실행한다.
-
요청 비동기 실행하기를 this의 소스 핸들, operation, request로 실행한다.
NOTE:
새 커서 데이터가 로드되기 전 이 메서드를 두 번 이상 호출하면(예: 같은 onsuccess 핸들러 내에서 continue()
를 두 번 호출하면) 두 번째 호출 시 "InvalidStateError
"
DOMException
이 발생합니다. 이는 커서의 got value flag가 false로 설정되었기 때문입니다.
continuePrimaryKey(key, primaryKey)
메서드 단계는 다음과 같습니다:
-
transaction의 상태가 활성이 아니면, throw "
TransactionInactiveError
"DOMException
을 발생시킨다. -
this의 소스 또는 실효 오브젝트 스토어가 삭제된 경우, throw "
InvalidStateError
"DOMException
을 발생시킨다. -
this의 소스가 인덱스가 아니면, throw "
InvalidAccessError
"DOMException
을 발생시킨다. -
this의 방향이 "
next
" 또는 "prev
"가 아니면, throw "InvalidAccessError
"DOMException
을 발생시킨다. -
this의 got value flag가 false이면(커서가 반복 중이거나 끝까지 반복된 경우), throw "
InvalidStateError
"DOMException
을 발생시킨다. -
r을 값을 키로 변환하기의 결과로 key를 사용하여 얻는다. 예외가 발생하면 다시 던진다.
-
r이 "invalid value" 또는 "invalid type"이면, throw "
DataError
"DOMException
을 발생시킨다. -
key를 r로 설정한다.
-
r을 값을 키로 변환하기의 결과로 primaryKey를 사용하여 얻는다. 예외가 발생하면 다시 던진다.
-
r이 "invalid value" 또는 "invalid type"이면, throw "
DataError
"DOMException
을 발생시킨다. -
primaryKey를 r로 설정한다.
-
key가 보다 작고 this의 포지션이고, this의 방향이 "
next
"이면, throw "DataError
"DOMException
을 발생시킨다. -
key가 보다 크고 this의 포지션이고, this의 방향이 "
prev
"이면, throw "DataError
"DOMException
을 발생시킨다. -
key가 같고 this의 포지션이며, primaryKey가 보다 작거나 같고 this의 오브젝트 스토어 포지션이고, this의 방향이 "
next
"이면, throw "DataError
"DOMException
을 발생시킨다. -
key가 같고 this의 포지션이며, primaryKey가 보다 크거나 같고 this의 오브젝트 스토어 포지션이고, this의 방향이 "
prev
"이면, throw "DataError
"DOMException
을 발생시킨다. -
this의 got value flag를 false로 설정한다.
-
request의 processed flag를 false로 설정한다.
-
request의 done flag를 false로 설정한다.
-
operation을 커서 반복하기 알고리즘으로, 현재 Realm record, this, key, primaryKey로 실행한다.
-
요청 비동기 실행하기를 this의 소스 핸들, operation, request로 실행한다.
참고:
새 커서 데이터가 로드되기 전에 이 메서드를 두 번 이상 호출하면(예: 같은 onsuccess 핸들러에서 continuePrimaryKey()
를 두 번 호출하면), 두 번째 호출 시 "InvalidStateError
"
DOMException
이 발생합니다. 이는 커서의 got value flag가 false로 설정되었기 때문입니다.
ReadOnlyError
"
DOMException
을 발생시키며,
트랜잭션이 활성 상태가 아닐 때 호출하면
"TransactionInactiveError
"
DOMException
을 발생시킵니다.
update(value)
메서드 단계는 다음과 같습니다:
-
transaction의 상태가 활성이 아니면, throw "
TransactionInactiveError
"DOMException
을 발생시킨다. -
transaction이 읽기 전용 트랜잭션이면, throw "
ReadOnlyError
"DOMException
을 발생시킨다. -
this의 소스 또는 실효 오브젝트 스토어가 삭제된 경우, throw "
InvalidStateError
"DOMException
을 발생시킨다. -
this의 got value flag가 false이면(커서가 반복 중이거나 끝까지 반복된 경우), throw "
InvalidStateError
"DOMException
을 발생시킨다. -
this의 key only flag가 true면, throw "
InvalidStateError
"DOMException
을 발생시킨다. -
targetRealm을 user-agent가 정의한 Realm으로 설정한다.
-
clone을 targetRealm의 transaction 동안 value의 복제본으로 설정한다. 예외가 발생하면 다시 던진다.
값의 복제본을 만드는 이유?
값은 저장 시 직렬화되므로, 여기서 복사본으로 취급하면 이 명세의 다른 알고리즘이 이를 ECMAScript 값으로 다룰 수 있게 합니다. 단, 구현체는 동작 차이가 관찰되지 않는다면 최적화할 수 있습니다. -
this의 실효 오브젝트 스토어가 인라인 키를 사용한다면,
-
kpk를 clone과 키 경로로 값에서 키 경로로 키 추출하기의 결과로 얻는다. 예외가 발생하면 다시 던진다.
-
kpk가 실패하거나, 유효하지 않거나, 같지 않으면 this의 실효 키와, throw "
DataError
"DOMException
을 발생시킨다.
-
-
operation을 오브젝트 스토어에 레코드 저장하기 알고리즘으로, this의 실효 오브젝트 스토어, clone, this의 실효 키, false로 실행한다.
-
요청 비동기 실행하기를 this, operation으로 실행한 결과(
IDBRequest
)를 반환한다.
참고: 오브젝트 스토어에 레코드 저장 결과는, 커서가 이동한 이후 레코드가 삭제되었다면 새 레코드가 생성된다는 점입니다.
delete()
메서드 단계는 다음과 같습니다:
-
transaction의 상태가 활성이 아니면, throw "
TransactionInactiveError
"DOMException
을 발생시킨다. -
transaction이 읽기 전용 트랜잭션이면, throw "
ReadOnlyError
"DOMException
을 발생시킨다. -
this의 소스 또는 실효 오브젝트 스토어가 삭제된 경우, throw "
InvalidStateError
"DOMException
을 발생시킨다. -
this의 got value flag가 false이면(커서가 반복 중이거나 끝까지 반복된 경우), throw "
InvalidStateError
"DOMException
을 발생시킨다. -
this의 key only flag가 true이면, throw "
InvalidStateError
"DOMException
을 발생시킨다. -
operation을 오브젝트 스토어에서 레코드 삭제하기 알고리즘으로, this의 실효 오브젝트 스토어, this의 실효 키로 실행한다.
-
요청 비동기 실행하기를 this, operation으로 실행한 결과(
IDBRequest
)를 반환한다.
커서의 key only flag
가 false로 설정된 경우,
IDBCursorWithValue
인터페이스도 구현합니다.
[Exposed =(Window ,Worker )]interface :
IDBCursorWithValue IDBCursor {readonly attribute any 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 단계는 다음과 같습니다:
-
names를 리스트로, scope에 있는 오브젝트 스토어 이름들의 목록으로 설정한다.
-
names로 정렬된 이름 목록 생성하기의 결과(
DOMStringList
)를 반환한다.
참고: 이 속성에서 반환되는 각 리스트의 내용은 변경되지 않지만, 업그레이드 트랜잭션 중에 이후 호출 시 오브젝트 스토어가 생성·삭제됨에 따라 다른 내용을 포함할 수 있습니다.
mode
getter 단계는
this의 모드를 반환한다.
durability
getter 단계는
this의 내구성
힌트를 반환한다.
durability
속성은 이번 판에서 새로 추가되었습니다.
Chrome 82, Edge 82, Firefox 126, Safari 15에서 지원됩니다.
🚧
db
getter 단계는
this의
connection에
연결된 데이터베이스를 반환합니다.
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)
메서드 단계는 다음과
같습니다:
-
this의 상태가 종료됨이면, throw "
InvalidStateError
"DOMException
을 발생시킨다. -
store를 오브젝트 스토어 중 이름이 name인 것을 this의 scope에서 찾는다. 없으면 throw "
NotFoundError
"DOMException
을 발생시킨다. -
store와 this에 연결된 오브젝트 스토어 핸들을 반환한다.
참고:
동일한 IDBTransaction
인스턴스에서 같은 이름으로 이 메서드를 호출하면 항상 동일한 IDBObjectStore
인스턴스를 반환합니다.
참고:
반환된 IDBObjectStore
인스턴스는 해당
IDBTransaction
전용입니다.
다른 IDBTransaction
에서
호출하면
다른 IDBObjectStore
인스턴스가 반환됩니다.
abort()
메서드 단계는 다음과 같습니다:
-
this의 상태가 커밋 중 또는 종료됨이면, throw "
InvalidStateError
"DOMException
을 발생시킨다.
commit()
메서드 단계는 다음과 같습니다:
-
this의 상태가 활성이 아니면, throw "
InvalidStateError
"DOMException
을 발생시킨다.
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로 데이터베이스 연결을 열기 위한 단계는 다음과 같다:
-
queue를 storageKey와 name에 대한 연결 큐로 설정한다.
-
request를 queue에 추가한다.
-
queue의 이전 모든 요청이 처리될 때까지 기다린다.
-
db를 storageKey 내에서 name 이름의 데이터베이스로 설정하고, 없으면 null로 한다.
-
version이 undefined이면, db가 null이면 version을 1로, 아니면 db의 버전으로 설정한다.
-
db가 null이면, db를 새 데이터베이스로 생성한다. 이름은 name, 버전은 0, 오브젝트 스토어는 없음으로 한다. 실패하면 적절한 에러(예:
QuotaExceededError
, 또는 "UnknownError
"DOMException
)를 반환한다. -
db의 버전이 version보다 크면, 새로 생성된 "
VersionError
"DOMException
을 반환하고 이 단계를 중단한다. -
connection을 db에 대한 새로운 연결로 설정한다.
-
connection의 버전을 version으로 설정한다.
-
db의 버전이 version보다 작으면, 다음을 수행한다:
-
openConnections를 db에 연결된, connection을 제외한 모든 연결 집합으로 설정한다.
-
openConnections의 각 entry에 대해, close pending flag가 true가 아니면, 데이터베이스 태스크를 큐에 추가하여, versionchange 이벤트를 발생시킨다. 이벤트 이름은
versionchange
이고, entry에 db의 버전과 version을 함께 전달한다.참고: 이 이벤트를 발생시키면 openConnections의 다른 객체들 중 하나 이상이 닫힐 수 있으며, 그런 경우 해당 객체에는
versionchange
이벤트가 발생하지 않는다. 이는 아직 이벤트가 발생하지 않았더라도 마찬가지다. -
모든 이벤트가 발생할 때까지 기다린다.
-
openConnections의 연결 중 아직 닫히지 않은 것이 있다면, 데이터베이스 태스크를 큐에 추가하여 version change 이벤트를 발생시킨다. 이벤트 이름은
blocked
이고, request에 db의 버전과 version을 전달한다. -
데이터베이스 업그레이드를 connection, version, request로 실행한다.
-
connection이 닫힌 경우라면, 새로 생성된 "
AbortError
"DOMException
을 반환하고 이 단계를 중단한다. -
request의 에러가 설정되어 있다면, 데이터베이스 연결 닫기 단계를 connection으로 실행하고, 새로 생성된 "
AbortError
"DOMException
을 반환하고 이 단계를 중단한다.
-
-
connection을 반환한다.
5.2. 데이터베이스 연결 닫기
connection 객체와 선택적인 forced flag로 데이터베이스 연결을 닫기 위한 단계는 다음과 같다:
-
connection의 close pending flag를 true로 설정한다.
-
forced flag가 true인 경우, connection을 사용하여 생성된 각 transaction에 대해 트랜잭션 중단하기를 transaction과 새로 생성된 "
AbortError
"DOMException
으로 실행한다. -
connection을 사용하여 생성된 모든 트랜잭션이 완료될 때까지 기다린다. 완료되면 connection은 닫힘 상태가 된다.
-
forced flag가 true인 경우, 이벤트를 발생시킨다. 이벤트 이름은
close
이고, connection에서 발생시킨다.참고:
close
이벤트는 연결이 비정상적으로 닫힐 때만 발생한다. 예를 들어 storage key의 저장소가 비워지거나, 손상 또는 I/O 오류가 발생한 경우이다.close()
가 명시적으로 호출된 경우에는 이벤트가 발생하지 않는다.
참고: connection의 close pending flag가 true로 설정된 후에는, 해당 connection을 통해 새 트랜잭션을 생성할 수 없다. 트랜잭션을 생성하는 모든 메서드는 먼저 connection의 close pending flag를 확인하고 true이면 예외를 발생시킨다.
참고: connection이 닫히면, 데이터베이스 업그레이드를 위한 단계와 데이터베이스 삭제 단계를 둘 다 대기시킬 수 있으며, database에 대한 connection들이 닫히기 전까지 진행하지 않는다.
5. 데이터베이스 삭제
storageKey가 삭제를 요청한 데이터베이스와 데이터베이스 name, request로 데이터베이스 삭제 단계는 다음과 같다:
-
queue를 storageKey와 name에 대한 연결 큐로 설정한다.
-
request를 queue에 추가한다.
-
queue에 있는 모든 이전 요청이 처리될 때까지 기다린다.
-
db를 storageKey 내에서 name 이름의 데이터베이스로 설정한다. 존재하지 않으면 0(영)을 반환한다.
-
openConnections를 db에 연결된 모든 연결 집합으로 설정한다.
-
openConnections의 각 entry에 대해, close pending flag가 true가 아니면, 데이터베이스 태스크 큐에 추가하여 versionchange 이벤트 발생시킨다. 이벤트 이름은
versionchange
이고, entry에 db의 버전과 null을 전달한다.참고: 이 이벤트를 발생시키면 openConnections의 다른 객체들 중 하나 이상이 닫힐 수 있으며, 그런 경우 해당 객체에는
versionchange
이벤트가 발생하지 않는다. 이는 아직 이벤트가 발생하지 않았더라도 마찬가지다. -
모든 이벤트가 발생할 때까지 기다린다.
-
openConnections의 연결 중 아직 닫히지 않은 것이 있다면, 데이터베이스 태스크 큐에 추가하여 versionchange 이벤트 발생시킨다. 이벤트 이름은
blocked
이고, request에 db의 버전과 null을 전달한다. -
version을 db의 버전으로 설정한다.
-
db를 삭제한다. 실패하면 적절한 에러(예:
QuotaExceededError
, 또는 "UnknownError
"DOMException
)를 반환한다. -
version을 반환한다.
5.4. 트랜잭션 커밋
transaction을 커밋하기 위한 트랜잭션 커밋 단계는 다음과 같다:
-
다음 단계를 병렬로 실행한다:
-
transaction의 request list의 모든 항목이 처리됨 상태가 될 때까지 기다린다.
-
transaction에 의해 이루어진 모든 미처리 변경사항을 데이터베이스에 기록하려 시도한다. 이 때 transaction의 내구성 힌트를 고려한다.
-
변경사항을 데이터베이스에 기록하는 동안 에러가 발생하면, 트랜잭션 중단하기 단계를 transaction과 에러에 적합한 타입(예:
QuotaExceededError
또는 "UnknownError
"DOMException
)로 실행하고, 이 단계를 종료한다. -
데이터베이스 태스크 큐에 추가하여 다음 단계를 실행한다:
-
transaction이 업그레이드 트랜잭션이면, transaction의 connection에 연결된 데이터베이스의 업그레이드 트랜잭션을 null로 설정한다.
-
이벤트를 발생시킨다. 이벤트 이름은
complete
이고, transaction에서 발생시킨다.참고: 이 이벤트 핸들러 중 하나에서 예외가 발생해도 트랜잭션은 이미 커밋된다. 데이터베이스 변경사항이 먼저 기록된 후에 이벤트가 발생하기 때문이다. 트랜잭션이 성공적으로 기록된 이후에
complete
이벤트가 발생한다. -
transaction이 업그레이드 트랜잭션이면, transaction에 연결된 request를 request로 설정하고, request의 transaction을 null로 설정한다.
-
-
5.5. 트랜잭션 중단
transaction을 중단할 때, error와 함께 트랜잭션 중단 단계는 다음과 같다:
-
transaction이 database에 가한 모든 변경사항을 되돌린다. 업그레이드 트랜잭션의 경우, 오브젝트 스토어 집합과 인덱스의 변경, 버전 변경도 포함된다. 트랜잭션 중에 생성된 모든 오브젝트 스토어와 인덱스는 이제 다른 알고리즘에서는 삭제된 것으로 간주된다.
-
transaction이 업그레이드 트랜잭션이면, 업그레이드 트랜잭션 중단 단계를 transaction으로 실행한다.
참고: 이는 transaction에 연결된 모든 connection, 오브젝트 스토어 핸들, 인덱스 핸들 인스턴스의 변경사항도 되돌린다.
-
transaction의 에러를 error로 설정한다.
-
transaction의 request list의 각 request에 대해, 비동기 요청 실행 단계를 중단하고, request의 processed flag를 true로 설정하며, 데이터베이스 태스크 큐에 추가하여 다음 단계를 실행한다:
-
request의 done flag를 true로 설정한다.
-
request의 result를 undefined로 설정한다.
-
request의 에러를 새로 생성된 "
AbortError
"DOMException
으로 설정한다. -
이벤트를 발생시킨다. 이벤트 이름은
error
이고, request에서 발생시키며bubbles
와cancelable
속성을 true로 초기화한다.
참고: 항상
error
이벤트가 발생하는 것은 아니다. 예를 들어 트랜잭션이 커밋 중 에러로 중단되거나, 실패한 요청이 마지막 남은 요청인 경우 등이다. -
-
데이터베이스 태스크 큐에 추가하여 다음 단계를 실행한다:
-
transaction이 업그레이드 트랜잭션이면, transaction의 connection에 연결된 database의 upgrade transaction을 null로 설정한다.
-
이벤트를 발생시킨다. 이벤트 이름은
abort
이고, transaction에서 발생시키며bubbles
속성을 true로 초기화한다. -
transaction이 업그레이드 트랜잭션이면:
-
request를 transaction에 연결된 open request로 설정한다.
-
request의 transaction을 null로 설정한다.
-
request의 result를 undefined로 설정한다.
-
request의 processed flag를 false로 설정한다.
-
request의 done flag를 false로 설정한다.
-
-
5.6. 데이터베이스에서 request를 비동기적으로 실행하기
source 객체와 데이터베이스에서 수행할 operation, 선택적 request로 비동기적으로 요청 실행 단계는 다음과 같다:
생성된 request가 속한 트랜잭션이 중단된 경우, 언제든지 트랜잭션 중단 단계에 따라 이 과정을 중단할 수 있다.
-
transaction을 source에 연결된 트랜잭션으로 설정한다.
-
request를 transaction의 request list 끝에 추가한다.
-
다음 단계를 병렬로 실행한다:
-
request가 transaction의 request list 중 processed가 아닌 첫 번째 항목이 될 때까지 기다린다.
-
result를 operation을 수행한 결과로 설정한다.
-
result가 에러이고 transaction의 상태가 커밋 중이면, 트랜잭션 중단 단계를 transaction과 result로 실행하고, 이 단계를 종료한다.
-
result가 에러이면, operation에 의해 이루어진 모든 변경사항을 되돌린다.
참고: 이는 해당 요청에 의해 이루어진 변경만 되돌리며, 트랜잭션에 의해 이루어진 다른 변경사항은 되돌리지 않는다.
-
request의 processed flag를 true로 설정한다.
-
데이터베이스 태스크 큐에 추가하여 다음 단계를 실행한다:
-
-
request를 반환한다.
5.7. 데이터베이스 업그레이드
connection(connection)과 새로운 version, request로 데이터베이스 업그레이드 단계를 실행하려면 다음을 따른다:
-
db를 connection의 데이터베이스로 설정한다.
-
transaction을 connection을 connection으로 사용하는 새로운 업그레이드 트랜잭션으로 생성한다.
-
transaction의 scope를 connection의 object store set으로 설정한다.
-
db의 업그레이드 트랜잭션을 transaction으로 설정한다.
-
transaction을 시작한다.
참고: 이 트랜잭션이 종료될 때까지, 같은 데이터베이스에 대해 다른 connection을 열 수 없다.
-
old version을 db의 버전으로 설정한다.
-
db의 버전을 version으로 설정한다. 이 변경은 트랜잭션의 일부로 간주되며, 트랜잭션이 중단되면 변경이 되돌려진다.
-
request의 processed flag를 true로 설정한다.
-
데이터베이스 태스크 큐에 추가하여 다음 단계를 실행한다:
-
request의 result를 connection으로 설정한다.
-
request의 transaction을 transaction으로 설정한다.
-
request의 done flag를 true로 설정한다.
-
didThrow를 versionchange 이벤트 발생 결과로 설정한다. 이벤트 이름은
upgradeneeded
이고, request에서 old version과 version을 전달한다. -
-
didThrow가 true이면, 트랜잭션 중단 단계를 transaction과 새로 생성된 "
AbortError
"DOMException
으로 실행한다.
-
-
transaction이 종료될 때까지 기다린다.
참고: 트랜잭션의 수명 동안 호출되는 일부 알고리즘(예: 트랜잭션 커밋 단계, 트랜잭션 중단 단계 등)은 업그레이드 트랜잭션에 특화된 단계를 포함한다.
5.8. 업그레이드 트랜잭션 중단
transaction으로 업그레이드 트랜잭션 중단 단계는 다음과 같다:
참고: 이 단계는 트랜잭션 중단 단계에 의해 필요할 때마다 실행되며, 데이터베이스의 변경사항(예: 연결된 오브젝트 스토어 및 인덱스 집합, 버전 변경 등)을 되돌린다.
-
connection을 transaction의 connection으로 설정한다.
-
database를 connection의 database로 설정한다.
-
connection의 version을 database가 기존에 존재했으면 database의 version으로, 새로 생성된 경우 0(영)으로 설정한다.
참고: 이는
version
속성 값을IDBDatabase
객체에서 반환되는 값으로 되돌린다. -
connection의 object store set을 database가 기존에 존재했으면 database의 오브젝트 스토어 집합으로, 새로 생성된 경우 빈 집합으로 설정한다.
참고: 이는
objectStoreNames
속성 값을IDBDatabase
객체에서 반환되는 값으로 되돌린다. -
transaction에 연관된 각 오브젝트 스토어 핸들 handle에 대해(트랜잭션 중에 생성되거나 삭제된 오브젝트 스토어에 대한 핸들도 포함):
-
handle의 object store가 트랜잭션 중 새로 생성된 것이 아니면, handle의 name을 object store의 name으로 설정한다.
-
handle의 index set을 해당 object store를 참조하는 인덱스 집합으로 설정한다.
참고: 이는 연관된
name
및indexNames
속성 값을IDBObjectStore
객체에서 반환되는 값으로 되돌린다.어떻게 관찰 가능한가?
스크립트는 트랜잭션이 중단된 후IDBTransaction
인스턴스에서objectStore()
메서드를 통해 오브젝트 스토어에 접근할 수는 없지만,IDBObjectStore
인스턴스에 대한 참조는 가질 수 있으며, 이때name
및indexNames
속성을 쿼리할 수 있다. -
-
transaction에 연관된 각 인덱스 핸들 handle에 대해(트랜잭션 중에 생성되거나 삭제된 인덱스에 대한 핸들도 포함):
참고:
name
속성은 IDBDatabase
인스턴스에서 수정되지 않는다. 업그레이드 트랜잭션을 중단할 때 새로운 데이터베이스를 생성 중이어도 마찬가지이다.
5.9. 성공 이벤트 발생
request에서 성공 이벤트 발생 단계는 다음과 같다:
-
event의
type
속성을 "success
"로 설정한다. -
event의
bubbles
및cancelable
속성을 false로 설정한다. -
transaction을 request의 트랜잭션으로 설정한다.
-
legacyOutputDidListenersThrowFlag를 초기값 false로 설정한다.
-
이벤트 디스패치를 request에서 event와 legacyOutputDidListenersThrowFlag로 실행한다.
-
-
legacyOutputDidListenersThrowFlag가 true이면, 트랜잭션 중단 단계에 따라 transaction과 새로 생성된 "
AbortError
"DOMException
으로 실행한다. -
transaction의 request list가 비어 있으면, 트랜잭션 커밋 단계를 transaction으로 실행한다.
5.10. 에러 이벤트 발생
request에서 에러 이벤트 발생 단계는 다음과 같다:
-
event의
type
속성을 "error
"로 설정한다. -
event의
bubbles
및cancelable
속성을 true로 설정한다. -
transaction을 request의 트랜잭션으로 설정한다.
-
legacyOutputDidListenersThrowFlag를 초기값 false로 설정한다.
-
이벤트 디스패치를 request에서 event와 legacyOutputDidListenersThrowFlag로 실행한다.
-
-
legacyOutputDidListenersThrowFlag가 true이면, 트랜잭션 중단 단계에 따라 transaction과 새로 생성된 "
AbortError
"DOMException
으로 실행하고, 이 단계를 종료한다. 이는 event의 canceled flag가 false여도 실행된다.참고: 에러 이벤트가 발생하고 이벤트 핸들러 중 하나에서 예외가 발생하면, transaction의
error
속성은 request의 error 대신AbortError
로 설정된다.preventDefault()
가 호출되지 않아도 마찬가지이다. -
event의 canceled flag가 false이면, 트랜잭션 중단 단계를 transaction과 request의 error로 실행하고, 이 단계를 종료한다.
-
transaction의 request list가 비어 있으면, 트랜잭션 커밋 단계를 transaction으로 실행한다.
5.11. 값 복제하기
value를 targetRealm 내에서 transaction 중에 복제하려면 다음 단계를 따른다:
-
참고: 트랜잭션을 비활성으로 만드는 것은, 복제 작업 중에 getter나 기타 부수 효과가 트랜잭션에 추가 요청을 하지 못하도록 하기 위함이다.
-
serialized를 ? StructuredSerializeForStorage(value)의 결과로 설정한다.
-
clone을 ? StructuredDeserialize(serialized, targetRealm)의 결과로 설정한다.
-
clone을 반환한다.
5.12. 여러 항목을 가져오기 위한 요청 생성
targetRealm, sourceHandle, kind, queryOrOptions, 선택적 count로 오브젝트 스토어 또는 인덱스에서 여러 항목을 가져오는 요청 생성 단계는 다음과 같다:
-
source를 sourceHandle에서 가져온 인덱스 또는 오브젝트 스토어로 설정한다. sourceHandle이 인덱스 핸들이면, source는 연결된 인덱스이고, 아니면 source는 연결된 오브젝트 스토어이다.
-
source가 삭제된 경우, throw "
InvalidStateError
"DOMException
을 발생시킨다. -
source가 인덱스이고, source의 오브젝트 스토어가 삭제된 경우, throw "
InvalidStateError
"DOMException
을 발생시킨다. -
transaction을 sourceHandle의 트랜잭션으로 설정한다.
-
transaction의 상태가 활성이 아니면, throw "
TransactionInactiveError
"DOMException
을 발생시킨다. -
range를 키 범위로 설정한다.
-
direction을 커서 방향으로 설정한다.
-
is a potentially valid key range를 queryOrOptions로 실행한 결과가 true면:
-
range를 값을 키 범위로 변환(queryOrOptions)의 결과로 설정한다. 예외가 발생하면 다시 던진다.
-
direction을 "
next
"로 설정한다.
-
-
그 외의 경우:
-
range를 값을 키 범위로 변환(queryOrOptions["
query
"])의 결과로 설정한다. 예외가 발생하면 다시 던진다. -
count를 queryOrOptions["
count
"]로 설정한다. -
direction을 queryOrOptions["
direction
"]로 설정한다.
-
-
operation을 실행할 알고리즘으로 설정한다.
-
source가 인덱스면, operation을 retrieve multiple items from an index (targetRealm, source, range, kind, direction, count 있으면 포함)으로 설정한다.
-
그 외의 경우 operation을 retrieve multiple items from an object store (targetRealm, source, range, kind, direction, count 있으면 포함)으로 설정한다.
-
비동기적으로 요청 실행을 sourceHandle과 operation으로 실행한 결과(
IDBRequest
)를 반환한다.
참고:
range는 키 또는 키 범위 (IDBKeyRange
)일
수 있으며,
가져올 레코드 항목을
지정한다. null 또는 주어지지 않은 경우 제한 없는 키 범위가 사용된다.
count가 지정되어 있고 범위 내에 count보다 많은 레코드가 있으면, 처음 count개만 가져온다.
6. 데이터베이스 연산
이 섹션에서는 오브젝트 스토어와 인덱스에서 데이터베이스의 데이터를 대상으로 수행되는 다양한 연산을 설명한다. 이러한 연산은 비동기적으로 요청 실행 단계에 의해 실행된다.
참고: 아래 연산 단계에서 StructuredDeserialize() 호출은 오류를 발생시키지 않는다고 단언할 수 있다( ! 접두사로 표시됨). 이는 오직 StructuredSerializeForStorage()의 이전 출력값만을 대상으로 동작하기 때문이다.
6.1. 오브젝트 스토어 저장 연산
store, value, 선택적 key, no-overwrite flag로 레코드를 오브젝트 스토어에 저장하려면 다음 단계를 따른다:
-
store가 키 생성기를 사용하는 경우:
-
key가 undefined인 경우:
-
key를 키 생성(store)의 결과로 설정한다.
-
key가 실패인 경우, 이 연산은 "
ConstraintError
"DOMException
으로 실패한다. 추가 단계 없이 이 알고리즘을 중단한다. -
store가 인라인 키도 사용하는 경우, 키 경로를 이용해 값에 키 주입 단계를 value, key, store의 키 경로로 실행한다.
-
-
그 외의 경우, 키 생성기 업데이트 가능 단계를 store와 key로 실행한다.
-
-
no-overwrite flag가 true로 지정된 경우, store에 key와 같은 키를 가진 레코드가 이미 존재하면, 이 연산은 "
ConstraintError
"DOMException
으로 실패한다. 추가 단계 없이 이 알고리즘을 중단한다. -
store에 key와 같은 키를 가진 레코드가 이미 존재하면, 오브젝트 스토어에서 레코드 삭제 단계를 통해 store에서 해당 레코드를 제거한다.
-
store에 key를 키로 하고, ! StructuredSerializeForStorage(value) 를 값으로 하는 레코드를 저장한다. 레코드는 오브젝트 스토어의 레코드 목록에 저장되며, 목록은 레코드의 키가 오름차순으로 정렬된다.
-
store를 참조하는 각 index에 대해:
-
index key를 키 경로를 이용해 값에서 키 추출 단계(value, index의 키 경로, index의 multiEntry 플래그)의 결과로 설정한다.
-
index key가 예외이거나, 유효하지 않거나, 실패이면, 해당 index에 대해 추가 동작 없이 다음 인덱스로 진행한다.
참고: 이 단계에서 발생한 예외는 다시 던지지 않는다.
-
index의 multiEntry 플래그가 false이거나, index key가 배열 키가 아니고, index에 키가 같은 index key인 레코드가 이미 존재하며, index의 unique 플래그가 true이면, 이 연산은 "
ConstraintError
"DOMException
으로 실패한다. 추가 단계 없이 이 알고리즘을 중단한다. -
index의 multiEntry 플래그가 true이고, index key가 배열 키이며, index에 키가 같은 subkeys 중 하나인 레코드가 이미 존재하며, index의 unique 플래그가 true이면, 이 연산은 "
ConstraintError
"DOMException
으로 실패한다. 추가 단계 없이 이 알고리즘을 중단한다. -
index의 multiEntry 플래그가 false이거나, index key가 배열 키가 아니라면, index에 index key를 키로 하고 key를 값으로 하는 레코드를 저장한다. 해당 레코드는 index의 레코드 목록에 저장되며, 목록은 키를 기준으로 우선 정렬하고, 값을 기준으로 2차 정렬하며, 모두 오름차순으로 정렬된다.
-
index의 multiEntry 플래그가 true이고, index key가 배열 키라면, subkeys의 각 subkey에 대해, index에 subkey를 키로 key를 값으로 하는 레코드를 저장한다. 해당 레코드는 index의 레코드 목록에 저장되며, 목록은 키 기준 우선, 값 기준 2차로 오름차순 정렬된다.
참고: subkeys가 없는 경우도 유효하며, 이 경우 인덱스에 아무 레코드도 추가되지 않는다.
참고: subkeys의 멤버가 배열 키여도, 해당 멤버 자체를 인덱스 레코드의 키로 바로 사용한다. 중첩된 배열 키는 펼치거나 여러 행으로 분해하지 않는다. 오직 가장 바깥 배열 키만 사용된다.
-
-
key를 반환한다.
6.2. 오브젝트 스토어 조회 연산
targetRealm, store, range로 오브젝트 스토어에서 값 조회하려면 다음 단계를 실행한다.
반환값은 undefined, ECMAScript 값, 또는 에러(DOMException
)이다:
-
record를 store의 레코드 목록 중 키가 range에 포함되는 첫 번째 레코드로 설정한다. 없다면 아무것도 선택하지 않는다.
-
record가 없으면 undefined를 반환한다.
-
serialized를 record의 값으로 설정한다. 만약 내부 저장소에서 값을 읽는 중 에러가 발생하면, 새로 생성된 "
NotReadableError
"DOMException
을 반환한다. -
! StructuredDeserialize(serialized, targetRealm)의 결과를 반환한다.
store, range로 오브젝트 스토어에서 키 조회하려면 다음 단계를 실행한다:
targetRealm, store, range, kind, direction, 선택적 count로 오브젝트 스토어에서 여러 항목 조회하려면 다음 단계를 실행한다:
-
count가 주어지지 않았거나 0(영)이면, count를 무한대로 설정한다.
-
records를 빈 목록으로 설정한다.
-
direction이 "
next
" 또는 "nextunique
"인 경우, store의 레코드 목록 중 키가 range에 포함되는 처음 count개의 레코드를 records로 설정한다. -
direction이 "
prev
" 또는 "prevunique
"인 경우, store의 레코드 목록 중 키가 range에 포함되는 마지막 count개를 records로 설정한다. -
list를 빈 목록으로 설정한다.
-
records의 각 record에 대해 kind에 따라 분기한다:
- "key"
- "value"
-
-
serialized를 record의 값으로 설정한다.
-
value를 ! StructuredDeserialize(serialized, targetRealm) 결과로 설정한다.
-
list에 value를 추가한다.
-
- "record"
-
-
key를 record의 키로 설정한다.
-
serialized를 record의 값으로 설정한다.
-
value를 ! StructuredDeserialize(serialized, targetRealm) 결과로 설정한다.
-
recordSnapshot을 레코드 스냅샷으로 새로 생성하고 key에 key, value에 value, primary key에 key를 설정한다.
-
list에 recordSnapshot을 추가한다.
-
-
list를 반환한다.
6.3. 인덱스 검색 작업
targetRealm, index, range로 인덱스에서 참조된 값 검색하기 단계:
-
record를 index의 레코드 목록(list of records) 중 range에 포함되는(in) 키(key)를 가진 첫 번째 레코드(record)로 설정한다.
-
record가 없으면 undefined를 반환한다.
-
serialized를 record의 참조 값(referenced value)으로 설정한다.
-
! StructuredDeserialize(serialized, targetRealm)를 반환한다.
index, range로 인덱스에서 값 검색하기 단계:
-
record를 index의 레코드 목록(list of records) 중 range에 포함되는(in) 키(key)를 가진 첫 번째 레코드(record)로 설정한다.
-
record가 없으면 undefined를 반환한다.
-
record의 값(value)으로 키를 값으로 변환하기의 결과를 반환한다.
targetRealm, index, range, kind, direction, 선택적 count로 인덱스에서 여러 항목 검색하기 단계:
-
count가 주어지지 않았거나 0이면, count를 infinity로 설정한다.
-
records를 빈 목록(list)으로 설정한다. 레코드(records) 타입이다.
-
direction에 따라:
- "next"
-
-
records를 index의 레코드 목록(list of records) 중 range에 포함되는(in) 키(key)를 가진 첫 count개로 설정한다.
-
- "nextunique"
-
-
rangeRecords를 index의 레코드 목록(list of records) 중 range에 포함되는(in) 키(key)를 가진 레코드들의 목록으로 설정한다.
-
rangeRecordsLength를 rangeRecords의 크기(size)로 설정한다.
-
i를 0으로 설정한다.
-
i가 rangeRecordsLength보다 작을 동안:
-
i를 1 증가시킨다.
-
키 비교(compare two keys)의 결과가 |rangeRecords[i]|와 |rangeRecords[i-1]|의 키를 비교해 같으면 continue한다.
-
그 외에는 append |rangeRecords[i]|를 records에 추가한다.
-
-
- "prev"
-
-
records를 index의 레코드 목록(list of records) 중 range에 포함되는(in) 키(key)를 가진 마지막 count개로 설정한다.
-
- "prevunique"
-
-
rangeRecords를 index의 레코드 목록(list of records) 중 range에 포함되는(in) 키(key)를 가진 레코드들의 목록으로 설정한다.
-
rangeRecordsLength를 rangeRecords의 크기(size)로 설정한다.
-
i를 0으로 설정한다.
-
i가 rangeRecordsLength보다 작을 동안:
-
i를 1 증가시킨다.
-
키 비교(compare two keys)의 결과가 |rangeRecords[i]|와 |rangeRecords[i-1]|의 키를 비교해 같으면 continue한다.
-
그 외에는 prepend |rangeRecords[i]|를 records에 추가한다.
-
-
-
list를 빈 목록(list)으로 설정한다.
-
각 records의 record에 대해, kind에 따라:
- "key"
-
-
key를 record의 값으로 키를 값으로 변환하기의 결과로 설정한다.
-
list에 key를 추가한다.
-
- "value"
-
-
serialized를 record의 참조 값(referenced value)으로 설정한다.
-
value를 ! StructuredDeserialize(serialized, targetRealm)의 결과로 설정한다.
-
list에 value를 추가한다.
-
- "record"
-
-
index key를 record의 키로 설정한다.
-
key를 record의 값으로 설정한다.
-
serialized를 record의 참조 값(referenced value)으로 설정한다.
-
value를 ! StructuredDeserialize(serialized, targetRealm)의 결과로 설정한다.
-
recordSnapshot을 index key를 key로, value를 value로, key를 primary key로 하는 새로운 레코드 스냅샷(record snapshot)으로 설정한다.
-
list에 recordSnapshot을 추가한다.
-
-
list를 반환한다.
6.4. 오브젝트 스토어 삭제 작업
store, range로 오브젝트 스토어에서 레코드 삭제하기 단계:
-
store의 레코드 목록(list of records)에서 range에 포함되는(in) 키를 가진 모든 레코드를 제거한다.
-
store를 참조하는 각 index에 대해, index의 레코드 목록(list of records)에서 값이 range에 포함되는(in) 모든 레코드(record)를 제거한다(해당 레코드가 존재하는 경우).
-
undefined를 반환한다.
6.5. 레코드 개수 세기 작업
source, range로 범위 내 레코드 개수 세기 단계:
-
count를 source의 레코드 중 range에 포함되는(in) 키를 가진 레코드 개수로 설정한다.
-
count를 반환한다.
6.6. 오브젝트 스토어 비우기 작업
store로 오브젝트 스토어 비우기 단계:
-
store에서 모든 레코드를 제거한다.
-
store를 참조하는 모든 인덱스(index)에서 모든 레코드(record)를 제거한다.
-
undefined를 반환한다.
6.7. 커서 반복 작업
targetRealm, cursor, 선택적 key, primaryKey (반복할 위치), 선택적 count로 커서 반복하기 단계:
-
source를 cursor의 source로 설정한다.
-
direction을 cursor의 direction으로 설정한다.
-
Assert: primaryKey가 주어지면, source는 인덱스(index)이고, direction은 "
next
" 또는 "prev
"여야 한다. -
records를 source의 레코드 목록으로 설정한다.
NOTE: records는 항상 오름차순 키 순서로 정렬되어 있다. source가 인덱스(index)인 경우, records는 오름차순 값(value) 순서로 2차 정렬된다 (여기서 인덱스의 값은 참조된 오브젝트 스토어의 레코드의 키임).
-
range를 cursor의 range로 설정한다.
-
position을 cursor의 position으로 설정한다.
-
object store position을 cursor의 object store position으로 설정한다.
-
count가 주어지지 않았다면, count를 1로 설정한다.
-
count가 0보다 클 때까지 반복:
-
direction에 따라 분기한다:
- "
next
" -
found record를 records 중 다음 조건을 모두 만족하는 첫 번째 레코드로 설정한다:
- "
nextunique
" -
found record를 records 중 다음 조건을 모두 만족하는 첫 번째 레코드로 설정한다:
- "
prev
" -
found record를 records 중 다음 조건을 모두 만족하는 마지막 레코드로 설정한다:
- "
prevunique
" -
temp record를 records 중 다음 조건을 모두 만족하는 마지막 레코드로 설정한다:
temp record가 있으면, found record를 records 중 key가 같은 첫 번째 레코드로 설정한다.
NOTE: "
prevunique
" 반복은 "nextunique
" 반복과 동일한 레코드를 역순으로 방문한다.
- "
-
found record가 없으면 다음을 실행한다:
-
cursor의 key를 undefined로 설정한다.
-
source가 인덱스라면, cursor의 object store position을 undefined로 설정한다.
-
cursor의 key only flag가 false라면, cursor의 value를 undefined로 설정한다.
-
null을 반환한다.
-
-
position을 found record의 키로 설정한다.
-
source가 인덱스라면, object store position을 found record의 값으로 설정한다.
-
count를 1 감소시킨다.
-
-
cursor의 position을 position으로 설정한다.
-
source가 인덱스라면, cursor의 object store position을 object store position으로 설정한다.
-
cursor의 key를 found record의 키로 설정한다.
-
cursor의 key only flag가 false라면:
-
serialized를 source가 오브젝트 스토어일 때 found record의 value로, 그 외에는 found record의 referenced value로 설정한다.
-
cursor의 value를 ! StructuredDeserialize(serialized, targetRealm)로 설정한다.
-
-
cursor의 got value flag를 true로 설정한다.
-
cursor를 반환한다.
7. ECMAScript 바인딩
이 섹션은 본 명세에서 정의된 키 값을 ECMAScript 값으로 변환하는 방법과 그 반대, 그리고 키 경로(key path)를 사용해 ECMAScript 값에서 추출하거나 주입하는 방법을 정의합니다. 이 섹션은 타입, 알고리즘, 그리고 ECMAScript 언어 명세의 일부 알고리즘 규칙을 참조합니다. [ECMA-262] 여기서 자세히 설명되지 않은 변환은 [WEBIDL]에서 정의됩니다.
7.1. 값에서 키 추출하기
value, keyPath, 선택적 multiEntry flag로 키 경로로 값에서 키 추출하기 단계. 이 단계의 결과는 키, invalid, failure, 또는 예외 발생일 수 있습니다.
-
r을 value, keyPath로 키 경로 평가(evaluating a key path on a value)의 결과로 설정합니다. 예외가 발생하면 다시 던집니다.
-
r이 failure면, failure를 반환합니다.
-
multiEntry flag가 false면 key를 r로 값을 키로 변환하기의 결과로, 그렇지 않으면 r로 값을 multiEntry 키로 변환하기의 결과로 설정합니다. 예외 발생 시 다시 던집니다.
-
key가 "invalid value" 또는 "invalid type"이면 invalid를 반환합니다.
-
key를 반환합니다.
value, keyPath로 키 경로로 값 평가하기 단계. 이 단계의 결과는 ECMAScript 값 또는 failure, 또는 예외 발생일 수 있습니다.
-
keyPath가 문자열 리스트라면:
-
result를
Array
객체(코드[]
와 같이 생성)로 새로 만듭니다. -
i를 0으로 설정합니다.
-
각 item에 대해 keyPath를 순회합니다:
-
key를 item, value로 재귀적으로 키 경로로 값 평가하기의 결과로 설정합니다.
-
Assert: key는 abrupt completion이 아닙니다.
-
key가 failure면, 전체 알고리즘을 중단하고 failure를 반환합니다.
-
status를 CreateDataProperty(result, p, key)의 결과로 설정합니다.
-
Assert: status는 true입니다.
-
i를 1 증가시킵니다.
-
-
result를 반환합니다.
NOTE: 키 경로 시퀀스는 중첩될 수 없으므로, 이 알고리즘은 재귀가 한 단계만 발생합니다.
-
-
keyPath가 빈 문자열이면 value를 반환하고 남은 단계는 건너뜁니다.
-
identifiers를 keyPath를 U+002E FULL STOP 문자(.)로 strictly splitting하여 얻은 결과로 설정합니다.
-
각 identifier에 대해 identifiers를 순회하며, 아래 단계로 이동합니다:
- 만약 Type(value)이 String이고,
identifier가 "
length
"이면 -
value를 value의 요소 개수(Number)로 설정합니다.
- 만약 value가
Array
이고, identifier가 "length
"이면 - 만약 value가
Blob
이고, identifier가 "size
"이면 -
value를 value의
size
와 같은 Number로 설정합니다. - 만약 value가
Blob
이고, identifier가 "type
"이면 -
value를 value의
type
과 같은 String으로 설정합니다. - 만약 value가
File
이고, identifier가 "name
"이면 -
value를 value의
name
과 같은 String으로 설정합니다. - 만약 value가
File
이고, identifier가 "lastModified
"이면 -
value를 value의
lastModified
와 같은 Number로 설정합니다. - 그 외의 경우
-
-
Type(value)이 Object가 아니면 failure를 반환합니다.
-
hop을 ! HasOwnProperty(value, identifier)의 결과로 설정합니다.
-
hop이 false면 failure를 반환합니다.
-
value가 undefined이면 failure를 반환합니다.
-
- 만약 Type(value)이 String이고,
identifier가 "
-
Assert: value는 abrupt completion이 아닙니다.
-
value를 반환합니다.
NOTE: 위 단계에서 Assertion이 가능한 이유는 이 알고리즘이 StructuredDeserialize의 출력값만 다루고 오직 "own" 속성만 접근하기 때문입니다.
7.2. 키를 값에 주입하기
NOTE: 이 섹션에서 사용하는 키 경로는 항상 문자열이며, 시퀀스가 아닙니다. 키 생성기를 사용하면서 키 경로가 시퀀스인 오브젝트 스토어를 만들 수 없기 때문입니다.
value와 keyPath로 키를 값에 주입할 수 있는지 확인하기 단계. 결과는 true 또는 false입니다.
-
identifiers를 keyPath를 U+002E FULL STOP 문자(.)로 strictly splitting한 결과로 설정합니다.
-
Assert: identifiers는 빈 값이 아닙니다.
-
identifiers의 마지막 항목을 제거합니다.
-
남은 identifiers 각각에 대해(순회),
NOTE: 위 단계에서 Assertion이 가능한 이유는 이 알고리즘이 StructuredDeserialize의 출력값만 다루기 때문입니다.
value, key, keyPath로 키 경로로 값에 키 주입하기 단계:
-
identifiers를 keyPath를 U+002E FULL STOP 문자(.)로 strictly splitting한 결과로 설정합니다.
-
Assert: identifiers는 빈 값이 아닙니다.
-
last를 identifiers의 마지막 항목으로 설정하고, 리스트에서 제거합니다.
-
남은 identifiers 각각에 대해(순회):
-
hop을 ! HasOwnProperty(value, identifier)의 결과로 설정합니다.
-
hop이 false이면:
-
o를
Object
({})로 새로 생성합니다. -
status를 CreateDataProperty(value, identifier, o)의 결과로 설정합니다.
-
Assert: status는 true입니다.
-
-
keyValue를 key로 키를 값으로 변환하기의 결과로 설정합니다.
-
status를 CreateDataProperty(value, last, keyValue)의 결과로 설정합니다.
-
Assert: status는 true입니다.
NOTE: 위 단계에서 Assertion이 가능한 이유는 이 알고리즘이 StructuredDeserialize의 출력값만 다루며, 키를 값에 주입할 수 있는지 확인하기 단계를 이미 실행했기 때문입니다.
7.3. 키를 값으로 변환하기
key로 키를 값으로 변환하기 단계. 결과는 ECMAScript 값입니다.
-
type을 key의 타입(type)으로 설정합니다.
-
value를 key의 값(value)으로 설정합니다.
-
type에 따라 분기합니다:
- number
-
value와 같은 ECMAScript Number 값을 반환합니다.
- string
-
value와 같은 ECMAScript String 값을 반환합니다.
- date
-
-
date를 ECMAScript Date 생성자에 value를 인자로 실행한 결과로 설정합니다.
-
Assert: date는 abrupt completion이 아닙니다.
-
date를 반환합니다.
-
- binary
-
-
len을 value의 길이(length)로 설정합니다.
-
buffer를 ECMAScript ArrayBuffer 생성자에 len을 인자로 실행한 결과로 설정합니다.
-
Assert: buffer는 abrupt completion이 아닙니다.
-
buffer의 [[ArrayBufferData]] 내부 슬롯에 value의 엔트리를 설정합니다.
-
buffer를 반환합니다.
-
- array
-
-
array를 ECMAScript Array 생성자를 인자 없이 실행한 결과로 설정합니다.
-
Assert: array는 abrupt completion이 아닙니다.
-
len을 value의 크기(size)로 설정합니다.
-
index를 0으로 설정합니다.
-
index가 len보다 작을 동안:
-
entry를 키를 값으로 변환하기(value[index])의 결과로 설정합니다.
-
status를 CreateDataProperty(array, index, entry)로 설정합니다.
-
Assert: status는 true입니다.
-
index를 1 증가시킵니다.
-
-
array를 반환합니다.
-
7.4. 값을 키로 변환하기
ECMAScript 값 input과 선택적 set seen으로 값을 키로 변환하기 단계. 결과는 키, "invalid value", "invalid type" 또는 예외 발생일 수 있습니다.
-
seen이 없으면, seen을 새로운 빈 set으로 설정합니다.
-
seen이 포함하는 input이 있으면 "invalid value"를 반환합니다.
-
아래에 해당하는 단계로 이동합니다:
- 만약 Type(input)이 Number라면
- input이
Date
이고([[DateValue]] 내부 슬롯이 있으면) - Type(input)이 String이라면
- input이 buffer source type이면
-
-
input이 detached이면 "invalid value"를 반환합니다.
-
bytes를 버퍼 소스가 가진 바이트를 복사(input)의 결과로 설정합니다.
-
- input이 Array exotic object이면
-
-
Append input을 seen에 추가합니다.
-
keys를 새로운 빈 리스트로 설정합니다.
-
index를 0으로 설정합니다.
-
index가 len보다 작을 동안:
-
hop를 ? HasOwnProperty(input, index)로 설정합니다.
-
hop이 false면 "invalid value"를 반환합니다.
-
key를 값을 키로 변환하기(entry, seen)의 결과로 설정합니다.
-
ReturnIfAbrupt(key).
-
key가 "invalid value" 또는 "invalid type"이면 이 단계들을 중단하고 "invalid value"를 반환합니다.
-
Append key를 keys에 추가합니다.
-
index를 1 증가시킵니다.
-
- 그 외의 경우
-
"invalid type"을 반환합니다.
ECMAScript 값 input으로 값을 multiEntry 키로 변환하기 단계. 결과는 키, "invalid value", "invalid type" 또는 예외 발생일 수 있습니다.
-
input이 Array exotic object라면:
-
seen을 set으로 새로 만들고 input만 포함합니다.
-
keys를 새로운 빈 목록(list)으로 설정합니다.
-
index를 0으로 설정합니다.
-
index가 len보다 작을 동안:
-
entry를 Get(input, index)로 설정합니다.
-
entry가 abrupt completion이 아니면:
-
key를 값을 키로 변환하기(entry, seen)의 결과로 설정합니다.
-
key가 "invalid value", "invalid type" 또는 abrupt completion이 아니고, keys에 item이 같은 것이 없으면, append key를 keys에 추가합니다.
-
-
index를 1 증가시킵니다.
-
-
그 외에는 값을 키로 변환하기(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 헤더와 설정값)를 활용해 여러 세션을 하나의 사용자 프로필로 조합할 수 있습니다.
8.2. 쿠키 부활(cookie resurrection)
영구 저장소의 사용자 인터페이스가 이 명세에서 설명된 영구 저장소의 데이터를 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판의 개정 이력은 해당 문서의 개정 이력을 참고하세요.
-
Indexed Database 트랜잭션 정리(cleanup) 알고리즘이 이제 다른 명세와 통합을 위해 값을 반환합니다. (PR #232)
-
WindowOrWorkerGlobalScope
가 이제mixin
이므로 부분 인터페이스 정의가 업데이트되었습니다. (PR #238) -
databases()
메서드가 추가되었습니다. (issue #31) -
commit()
메서드가 추가되었습니다. (issue #234) -
request
속성이 추가되었습니다. (issue #255) -
lastModifiedDate
속성을File
객체에서 처리하는 비표준 동작을 제거했습니다. (issue #215) -
includes()
메서드의 이스케이프 처리를 제거했습니다. (issue #294) -
배열 키를 Array exotic object로 제한(프록시 금지)하였습니다. (issue #309)
-
트랜잭션 복제(clone) 작업 중 일시적으로 비활성화 상태로 만듭니다. (PR #310)
-
durability
옵션 및durability
속성이 추가되었습니다. (issue #50) -
§ 2.7.2 트랜잭션 스케줄링을 더 정확하게 명시하고, 중첩된 범위에서 읽기 전용 트랜잭션이 실행 중일 때 읽기/쓰기 트랜잭션 시작을 금지합니다. (issue #253)
-
접근성 고려사항 섹션이 추가되었습니다. (issue #327)
-
[infra]의 목록 정렬 정의를 사용합니다. (issue #346)
-
live 트랜잭션 정의가 추가되었고, "run an upgrade transaction" 명칭을 upgrade a database로 변경해 의미를 명확히 했습니다. (issue #408)
-
§ 6.2 오브젝트 스토어 검색 작업에서 저장소에서 값을 읽을 때 실패 시
DOMException
타입을 명시합니다. (issue #423) -
분리된(detached) array buffer에 대해 값을 키로 변환하기가 invalid를 반환하도록 업데이트했습니다. (issue #417)
-
open()
이 요청의 processed flag를 true로 설정하게 업데이트했습니다. (issue #434) -
생성이 완료되지 않은 데이터베이스는
databases()
에 포함하지 않도록 명시했습니다. (issue #442) -
자동 커밋은 비활성(inactive) 트랜잭션만 시도해야 함을 명확히 했습니다. (issue #436)
-
중단된 트랜잭션을 처리하는 upgrade a database 단계를 수정했습니다. (issue #436)
-
커서 반복(iterate a cursor) 값 직렬화를 오브젝트 스토어의 경우 referenced value 대신 value를 사용하도록 업데이트했습니다. (issue #452)
-
source handle을 커서(cursor)에 추가하여 스크립트에서 내부 인덱스 및 오브젝트 스토어 노출을 방지합니다. (issue #445)
-
데이터베이스 작업 큐 추가(queue a database task)를 정의하고, queue a task를 이 알고리즘으로 대체했습니다. (issue #421)
-
databases
() 에 누락된 병렬 단계 추가 (issue #421) -
커서 반복 조건을 명확히 했습니다 (issue #450)
-
getAllRecords(options)
메서드를IDBObjectStore
및IDBIndex
에 추가했습니다. (issue #206) -
getAll()
및getAllKeys()
에 direction 옵션을IDBObjectStore
및IDBIndex
에 추가했습니다. (issue #130) -
QuotaExceededError
사용이DOMException
파생 인터페이스로 변경된 점을 반영했습니다. (issue #463) -
error가 null이 될 수 있고, 트랜잭션 중단에서 설정될 수 있음을 명시했습니다. (issue #433)
-
데이터베이스 연결 열기에서 upgrade transaction 대신 request의 error를 확인하도록 수정했습니다. (issue #433)
-
abort()
에서 중복된 트랜잭션 상태 변경을 제거했습니다.
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, 이 모든 분들의 피드백과 제안 덕분에 이 명세가 개선되었습니다.