Modern IDB:Make in-memory Index cursors work.
[WebKit.git] / Source / WebCore / Modules / indexeddb / client / IDBIndexImpl.cpp
1 /*
2  * Copyright (C) 2015 Apple 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  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "IDBIndexImpl.h"
28
29 #if ENABLE(INDEXED_DATABASE)
30
31 #include "DOMRequestState.h"
32 #include "IDBAnyImpl.h"
33 #include "IDBBindingUtilities.h"
34 #include "IDBCursorImpl.h"
35 #include "IDBDatabaseException.h"
36 #include "IDBKeyRangeData.h"
37 #include "IDBObjectStoreImpl.h"
38 #include "IDBTransactionImpl.h"
39 #include "Logging.h"
40
41 namespace WebCore {
42 namespace IDBClient {
43
44 Ref<IDBIndex> IDBIndex::create(const IDBIndexInfo& info, IDBObjectStore& objectStore)
45 {
46     return adoptRef(*new IDBIndex(info, objectStore));
47 }
48
49 IDBIndex::IDBIndex(const IDBIndexInfo& info, IDBObjectStore& objectStore)
50     : m_info(info)
51     , m_objectStore(objectStore)
52 {
53 }
54
55 IDBIndex::~IDBIndex()
56 {
57 }
58
59 const String& IDBIndex::name() const
60 {
61     return m_info.name();
62 }
63
64 RefPtr<WebCore::IDBObjectStore> IDBIndex::objectStore()
65 {
66     return &m_objectStore.get();
67 }
68
69 RefPtr<WebCore::IDBAny> IDBIndex::keyPathAny() const
70 {
71     return IDBAny::create(m_info.keyPath());
72 }
73
74 const IDBKeyPath& IDBIndex::keyPath() const
75 {
76     return m_info.keyPath();
77 }
78
79 bool IDBIndex::unique() const
80 {
81     return m_info.unique();
82 }
83
84 bool IDBIndex::multiEntry() const
85 {
86     return m_info.multiEntry();
87 }
88
89 RefPtr<WebCore::IDBRequest> IDBIndex::openCursor(ScriptExecutionContext* context, IDBKeyRange* range, const String& directionString, ExceptionCode& ec)
90 {
91     LOG(IndexedDB, "IDBIndex::openCursor");
92
93     if (m_deleted || m_objectStore->isDeleted()) {
94         ec = IDBDatabaseException::InvalidStateError;
95         return nullptr;
96     }
97
98     if (!m_objectStore->modernTransaction().isActive()) {
99         ec = IDBDatabaseException::TransactionInactiveError;
100         return nullptr;
101     }
102
103     IndexedDB::CursorDirection direction = IDBCursor::stringToDirection(directionString, ec);
104     if (ec)
105         return nullptr;
106
107     IDBKeyRangeData rangeData = range;
108     if (rangeData.lowerKey.isNull())
109         rangeData.lowerKey = IDBKeyData::minimum();
110     if (rangeData.upperKey.isNull())
111         rangeData.upperKey = IDBKeyData::maximum();
112
113     auto info = IDBCursorInfo::indexCursor(m_objectStore->modernTransaction(), m_objectStore->info().identifier(), m_info.identifier(), rangeData, direction, IndexedDB::CursorType::KeyAndValue);
114     Ref<IDBRequest> request = m_objectStore->modernTransaction().requestOpenCursor(*context, *this, info);
115     return WTF::move(request);
116 }
117
118 RefPtr<WebCore::IDBRequest> IDBIndex::openCursor(ScriptExecutionContext* context, const Deprecated::ScriptValue& key, const String& direction, ExceptionCode& ec)
119 {
120     LOG(IndexedDB, "IDBIndex::openCursor");
121     RefPtr<IDBKeyRange> keyRange = IDBKeyRange::only(context, key, ec);
122     if (ec)
123         return nullptr;
124
125     return openCursor(context, keyRange.get(), direction, ec);
126 }
127
128 RefPtr<WebCore::IDBRequest> IDBIndex::count(ScriptExecutionContext* context, ExceptionCode& ec)
129 {
130     LOG(IndexedDB, "IDBIndex::count");
131
132     if (!context) {
133         ec = INVALID_STATE_ERR;
134         return nullptr;
135     }
136
137     IDBKeyRangeData range;
138     range.isNull = false;
139     return doCount(*context, range, ec);}
140
141 RefPtr<WebCore::IDBRequest> IDBIndex::count(ScriptExecutionContext* context, IDBKeyRange* range, ExceptionCode& ec)
142 {
143     LOG(IndexedDB, "IDBIndex::count");
144
145     if (!context) {
146         ec = INVALID_STATE_ERR;
147         return nullptr;
148     }
149
150     return doCount(*context, IDBKeyRangeData(range), ec);
151 }
152
153 RefPtr<WebCore::IDBRequest> IDBIndex::count(ScriptExecutionContext* context, const Deprecated::ScriptValue& key, ExceptionCode& ec)
154 {
155     LOG(IndexedDB, "IDBIndex::count");
156
157     if (!context) {
158         ec = INVALID_STATE_ERR;
159         return nullptr;
160     }
161
162     DOMRequestState requestState(context);
163     RefPtr<IDBKey> idbKey = scriptValueToIDBKey(&requestState, key);
164     if (!idbKey || idbKey->type() == KeyType::Invalid) {
165         ec = static_cast<ExceptionCode>(IDBExceptionCode::DataError);
166         return nullptr;
167     }
168
169     return doCount(*context, IDBKeyRangeData(idbKey.get()), ec);
170 }
171
172 RefPtr<WebCore::IDBRequest> IDBIndex::doCount(ScriptExecutionContext& context, const IDBKeyRangeData& range, ExceptionCode& ec)
173 {
174     if (m_deleted || m_objectStore->isDeleted()) {
175         ec = INVALID_STATE_ERR;
176         return nullptr;
177     }
178
179     if (range.isNull) {
180         ec = static_cast<ExceptionCode>(IDBExceptionCode::DataError);
181         return nullptr;
182     }
183
184     auto& transaction = m_objectStore->modernTransaction();
185     if (!transaction.isActive()) {
186         ec = static_cast<ExceptionCode>(IDBExceptionCode::TransactionInactiveError);
187         return nullptr;
188     }
189
190     return transaction.requestCount(context, *this, range);
191 }
192
193 RefPtr<WebCore::IDBRequest> IDBIndex::openKeyCursor(ScriptExecutionContext* context, IDBKeyRange* range, const String& directionString, ExceptionCode& ec)
194 {
195     LOG(IndexedDB, "IDBIndex::openKeyCursor");
196
197     if (m_deleted || m_objectStore->isDeleted()) {
198         ec = IDBDatabaseException::InvalidStateError;
199         return nullptr;
200     }
201
202     if (!m_objectStore->modernTransaction().isActive()) {
203         ec = IDBDatabaseException::TransactionInactiveError;
204         return nullptr;
205     }
206
207     IndexedDB::CursorDirection direction = IDBCursor::stringToDirection(directionString, ec);
208     if (ec)
209         return nullptr;
210
211     auto info = IDBCursorInfo::indexCursor(m_objectStore->modernTransaction(), m_objectStore->info().identifier(), m_info.identifier(), range, direction, IndexedDB::CursorType::KeyOnly);
212     Ref<IDBRequest> request = m_objectStore->modernTransaction().requestOpenCursor(*context, *this, info);
213     return WTF::move(request);
214 }
215
216 RefPtr<WebCore::IDBRequest> IDBIndex::openKeyCursor(ScriptExecutionContext* context, const Deprecated::ScriptValue& key, const String& direction, ExceptionCode& ec)
217 {
218     LOG(IndexedDB, "IDBIndex::openKeyCursor");
219     RefPtr<IDBKeyRange> keyRange = IDBKeyRange::only(context, key, ec);
220     if (ec)
221         return nullptr;
222
223     return openKeyCursor(context, keyRange.get(), direction, ec);
224 }
225
226 RefPtr<WebCore::IDBRequest> IDBIndex::get(ScriptExecutionContext* context, IDBKeyRange* range, ExceptionCode& ec)
227 {
228     LOG(IndexedDB, "IDBIndex::get");
229
230     if (!context) {
231         ec = INVALID_STATE_ERR;
232         return nullptr;
233     }
234
235     return doGet(*context, IDBKeyRangeData(range), ec);
236 }
237
238 RefPtr<WebCore::IDBRequest> IDBIndex::get(ScriptExecutionContext* context, const Deprecated::ScriptValue& key, ExceptionCode& ec)
239 {
240     LOG(IndexedDB, "IDBIndex::get");
241
242     if (!context) {
243         ec = INVALID_STATE_ERR;
244         return nullptr;
245     }
246
247     DOMRequestState requestState(context);
248     RefPtr<IDBKey> idbKey = scriptValueToIDBKey(&requestState, key);
249     if (!idbKey || idbKey->type() == KeyType::Invalid) {
250         ec = static_cast<ExceptionCode>(IDBExceptionCode::DataError);
251         return nullptr;
252     }
253
254     return doGet(*context, IDBKeyRangeData(idbKey.get()), ec);
255 }
256
257 RefPtr<WebCore::IDBRequest> IDBIndex::doGet(ScriptExecutionContext& context, const IDBKeyRangeData& range, ExceptionCode& ec)
258 {
259     if (m_deleted || m_objectStore->isDeleted()) {
260         ec = INVALID_STATE_ERR;
261         return nullptr;
262     }
263
264     if (range.isNull) {
265         ec = static_cast<ExceptionCode>(IDBExceptionCode::DataError);
266         return nullptr;
267     }
268
269     auto& transaction = m_objectStore->modernTransaction();
270     if (!transaction.isActive()) {
271         ec = static_cast<ExceptionCode>(IDBExceptionCode::TransactionInactiveError);
272         return nullptr;
273     }
274
275     return transaction.requestGetValue(context, *this, range);
276 }
277
278 RefPtr<WebCore::IDBRequest> IDBIndex::getKey(ScriptExecutionContext* context, IDBKeyRange* range, ExceptionCode& ec)
279 {
280     LOG(IndexedDB, "IDBIndex::getKey");
281
282     if (!context) {
283         ec = INVALID_STATE_ERR;
284         return nullptr;
285     }
286
287     return doGetKey(*context, IDBKeyRangeData(range), ec);
288 }
289
290 RefPtr<WebCore::IDBRequest> IDBIndex::getKey(ScriptExecutionContext* context, const Deprecated::ScriptValue& key, ExceptionCode& ec)
291 {
292     LOG(IndexedDB, "IDBIndex::getKey");
293
294     if (!context) {
295         ec = INVALID_STATE_ERR;
296         return nullptr;
297     }
298
299     DOMRequestState requestState(context);
300     RefPtr<IDBKey> idbKey = scriptValueToIDBKey(&requestState, key);
301     if (!idbKey || idbKey->type() == KeyType::Invalid) {
302         ec = static_cast<ExceptionCode>(IDBExceptionCode::DataError);
303         return nullptr;
304     }
305
306     return doGetKey(*context, IDBKeyRangeData(idbKey.get()), ec);
307 }
308
309 RefPtr<WebCore::IDBRequest> IDBIndex::doGetKey(ScriptExecutionContext& context, const IDBKeyRangeData& range, ExceptionCode& ec)
310 {
311     if (m_deleted || m_objectStore->isDeleted()) {
312         ec = INVALID_STATE_ERR;
313         return nullptr;
314     }
315
316     if (range.isNull) {
317         ec = static_cast<ExceptionCode>(IDBExceptionCode::DataError);
318         return nullptr;
319     }
320
321     auto& transaction = m_objectStore->modernTransaction();
322     if (!transaction.isActive()) {
323         ec = static_cast<ExceptionCode>(IDBExceptionCode::TransactionInactiveError);
324         return nullptr;
325     }
326
327     return transaction.requestGetKey(context, *this, range);
328 }
329
330 } // namespace IDBClient
331 } // namespace WebCore
332
333 #endif // ENABLE(INDEXED_DATABASE)