1/* 2 * Copyright (C) 2010 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 21 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#include "config.h" 27#include "modules/indexeddb/IDBIndex.h" 28 29#include "bindings/v8/ExceptionState.h" 30#include "bindings/v8/IDBBindingUtilities.h" 31#include "core/dom/ExceptionCode.h" 32#include "core/dom/ExecutionContext.h" 33#include "modules/indexeddb/IDBDatabase.h" 34#include "modules/indexeddb/IDBKey.h" 35#include "modules/indexeddb/IDBTracing.h" 36#include "modules/indexeddb/IDBTransaction.h" 37#include "modules/indexeddb/WebIDBCallbacksImpl.h" 38#include "public/platform/WebIDBKeyRange.h" 39 40using blink::WebIDBDatabase; 41using blink::WebIDBCallbacks; 42 43namespace WebCore { 44 45IDBIndex::IDBIndex(const IDBIndexMetadata& metadata, IDBObjectStore* objectStore, IDBTransaction* transaction) 46 : m_metadata(metadata) 47 , m_objectStore(objectStore) 48 , m_transaction(transaction) 49 , m_deleted(false) 50{ 51 ASSERT(m_objectStore); 52 ASSERT(m_transaction); 53 ASSERT(m_metadata.id != IDBIndexMetadata::InvalidId); 54 ScriptWrappable::init(this); 55} 56 57IDBIndex::~IDBIndex() 58{ 59} 60 61ScriptValue IDBIndex::keyPath(ExecutionContext* context) const 62{ 63 DOMRequestState requestState(context); 64 return idbAnyToScriptValue(&requestState, IDBAny::create(m_metadata.keyPath)); 65} 66 67PassRefPtr<IDBRequest> IDBIndex::openCursor(ExecutionContext* context, const ScriptValue& range, const String& directionString, ExceptionState& exceptionState) 68{ 69 IDB_TRACE("IDBIndex::openCursor"); 70 if (isDeleted()) { 71 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::indexDeletedErrorMessage); 72 return 0; 73 } 74 if (m_transaction->isFinished()) { 75 exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionFinishedErrorMessage); 76 return 0; 77 } 78 if (!m_transaction->isActive()) { 79 exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionInactiveErrorMessage); 80 return 0; 81 } 82 IndexedDB::CursorDirection direction = IDBCursor::stringToDirection(directionString, exceptionState); 83 if (exceptionState.hadException()) 84 return 0; 85 86 RefPtr<IDBKeyRange> keyRange = IDBKeyRange::fromScriptValue(context, range, exceptionState); 87 if (exceptionState.hadException()) 88 return 0; 89 90 return openCursor(context, keyRange.release(), direction); 91} 92 93PassRefPtr<IDBRequest> IDBIndex::openCursor(ExecutionContext* context, PassRefPtr<IDBKeyRange> keyRange, IndexedDB::CursorDirection direction) 94{ 95 RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get()); 96 request->setCursorDetails(IndexedDB::CursorKeyAndValue, direction); 97 backendDB()->openCursor(m_transaction->id(), m_objectStore->id(), m_metadata.id, keyRange, direction, false, WebIDBDatabase::NormalTask, WebIDBCallbacksImpl::create(request).leakPtr()); 98 return request; 99} 100 101PassRefPtr<IDBRequest> IDBIndex::count(ExecutionContext* context, const ScriptValue& range, ExceptionState& exceptionState) 102{ 103 IDB_TRACE("IDBIndex::count"); 104 if (isDeleted()) { 105 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::indexDeletedErrorMessage); 106 return 0; 107 } 108 if (m_transaction->isFinished()) { 109 exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionFinishedErrorMessage); 110 return 0; 111 } 112 if (!m_transaction->isActive()) { 113 exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionInactiveErrorMessage); 114 return 0; 115 } 116 117 RefPtr<IDBKeyRange> keyRange = IDBKeyRange::fromScriptValue(context, range, exceptionState); 118 if (exceptionState.hadException()) 119 return 0; 120 121 RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get()); 122 backendDB()->count(m_transaction->id(), m_objectStore->id(), m_metadata.id, keyRange.release(), WebIDBCallbacksImpl::create(request).leakPtr()); 123 return request; 124} 125 126PassRefPtr<IDBRequest> IDBIndex::openKeyCursor(ExecutionContext* context, const ScriptValue& range, const String& directionString, ExceptionState& exceptionState) 127{ 128 IDB_TRACE("IDBIndex::openKeyCursor"); 129 if (isDeleted()) { 130 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::indexDeletedErrorMessage); 131 return 0; 132 } 133 if (m_transaction->isFinished()) { 134 exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionFinishedErrorMessage); 135 return 0; 136 } 137 if (!m_transaction->isActive()) { 138 exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionInactiveErrorMessage); 139 return 0; 140 } 141 IndexedDB::CursorDirection direction = IDBCursor::stringToDirection(directionString, exceptionState); 142 if (exceptionState.hadException()) 143 return 0; 144 145 RefPtr<IDBKeyRange> keyRange = IDBKeyRange::fromScriptValue(context, range, exceptionState); 146 if (exceptionState.hadException()) 147 return 0; 148 149 RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get()); 150 request->setCursorDetails(IndexedDB::CursorKeyOnly, direction); 151 backendDB()->openCursor(m_transaction->id(), m_objectStore->id(), m_metadata.id, keyRange.release(), direction, true, WebIDBDatabase::NormalTask, WebIDBCallbacksImpl::create(request).leakPtr()); 152 return request; 153} 154 155PassRefPtr<IDBRequest> IDBIndex::get(ExecutionContext* context, const ScriptValue& key, ExceptionState& exceptionState) 156{ 157 IDB_TRACE("IDBIndex::get"); 158 if (isDeleted()) { 159 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::indexDeletedErrorMessage); 160 return 0; 161 } 162 if (m_transaction->isFinished()) { 163 exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionFinishedErrorMessage); 164 return 0; 165 } 166 if (!m_transaction->isActive()) { 167 exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionInactiveErrorMessage); 168 return 0; 169 } 170 171 RefPtr<IDBKeyRange> keyRange = IDBKeyRange::fromScriptValue(context, key, exceptionState); 172 if (exceptionState.hadException()) 173 return 0; 174 if (!keyRange) { 175 exceptionState.throwDOMException(DataError, IDBDatabase::noKeyOrKeyRangeErrorMessage); 176 return 0; 177 } 178 179 RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get()); 180 backendDB()->get(m_transaction->id(), m_objectStore->id(), m_metadata.id, keyRange.release(), false, WebIDBCallbacksImpl::create(request).leakPtr()); 181 return request; 182} 183 184PassRefPtr<IDBRequest> IDBIndex::getKey(ExecutionContext* context, const ScriptValue& key, ExceptionState& exceptionState) 185{ 186 IDB_TRACE("IDBIndex::getKey"); 187 if (isDeleted()) { 188 exceptionState.throwDOMException(InvalidStateError, IDBDatabase::indexDeletedErrorMessage); 189 return 0; 190 } 191 if (m_transaction->isFinished()) { 192 exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionFinishedErrorMessage); 193 return 0; 194 } 195 if (!m_transaction->isActive()) { 196 exceptionState.throwDOMException(TransactionInactiveError, IDBDatabase::transactionInactiveErrorMessage); 197 return 0; 198 } 199 200 RefPtr<IDBKeyRange> keyRange = IDBKeyRange::fromScriptValue(context, key, exceptionState); 201 if (exceptionState.hadException()) 202 return 0; 203 if (!keyRange) { 204 exceptionState.throwDOMException(DataError, IDBDatabase::noKeyOrKeyRangeErrorMessage); 205 return 0; 206 } 207 208 RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get()); 209 backendDB()->get(m_transaction->id(), m_objectStore->id(), m_metadata.id, keyRange.release(), true, WebIDBCallbacksImpl::create(request).leakPtr()); 210 return request; 211} 212 213WebIDBDatabase* IDBIndex::backendDB() const 214{ 215 return m_transaction->backendDB(); 216} 217 218bool IDBIndex::isDeleted() const 219{ 220 return m_deleted || m_objectStore->isDeleted(); 221} 222 223} // namespace WebCore 224