f092580d7ad90d512ab104f519f3e196a009289f
[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     auto info = IDBCursorInfo::indexCursor(m_objectStore->modernTransaction(), m_info.identifier(), range, direction, IndexedDB::CursorType::KeyAndValue);
108     Ref<IDBRequest> request = m_objectStore->modernTransaction().requestOpenCursor(*context, *this, info);
109     return WTF::move(request);
110 }
111
112 RefPtr<WebCore::IDBRequest> IDBIndex::openCursor(ScriptExecutionContext* context, const Deprecated::ScriptValue& key, const String& direction, ExceptionCode& ec)
113 {
114     LOG(IndexedDB, "IDBIndex::openCursor");
115     RefPtr<IDBKeyRange> keyRange = IDBKeyRange::only(context, key, ec);
116     if (ec)
117         return nullptr;
118
119     return openCursor(context, keyRange.get(), direction, ec);
120 }
121
122 RefPtr<WebCore::IDBRequest> IDBIndex::count(ScriptExecutionContext* context, ExceptionCode& ec)
123 {
124     LOG(IndexedDB, "IDBIndex::count");
125
126     if (!context) {
127         ec = INVALID_STATE_ERR;
128         return nullptr;
129     }
130
131     IDBKeyRangeData range;
132     range.isNull = false;
133     return doCount(*context, range, ec);}
134
135 RefPtr<WebCore::IDBRequest> IDBIndex::count(ScriptExecutionContext* context, IDBKeyRange* range, ExceptionCode& ec)
136 {
137     LOG(IndexedDB, "IDBIndex::count");
138
139     if (!context) {
140         ec = INVALID_STATE_ERR;
141         return nullptr;
142     }
143
144     return doCount(*context, IDBKeyRangeData(range), ec);
145 }
146
147 RefPtr<WebCore::IDBRequest> IDBIndex::count(ScriptExecutionContext* context, const Deprecated::ScriptValue& key, ExceptionCode& ec)
148 {
149     LOG(IndexedDB, "IDBIndex::count");
150
151     if (!context) {
152         ec = INVALID_STATE_ERR;
153         return nullptr;
154     }
155
156     DOMRequestState requestState(context);
157     RefPtr<IDBKey> idbKey = scriptValueToIDBKey(&requestState, key);
158     if (!idbKey || idbKey->type() == KeyType::Invalid) {
159         ec = static_cast<ExceptionCode>(IDBExceptionCode::DataError);
160         return nullptr;
161     }
162
163     return doCount(*context, IDBKeyRangeData(idbKey.get()), ec);
164 }
165
166 RefPtr<WebCore::IDBRequest> IDBIndex::doCount(ScriptExecutionContext& context, const IDBKeyRangeData& range, ExceptionCode& ec)
167 {
168     if (m_deleted || m_objectStore->isDeleted()) {
169         ec = INVALID_STATE_ERR;
170         return nullptr;
171     }
172
173     if (range.isNull) {
174         ec = static_cast<ExceptionCode>(IDBExceptionCode::DataError);
175         return nullptr;
176     }
177
178     auto& transaction = m_objectStore->modernTransaction();
179     if (!transaction.isActive()) {
180         ec = static_cast<ExceptionCode>(IDBExceptionCode::TransactionInactiveError);
181         return nullptr;
182     }
183
184     return transaction.requestCount(context, *this, range);
185 }
186
187 RefPtr<WebCore::IDBRequest> IDBIndex::openKeyCursor(ScriptExecutionContext* context, IDBKeyRange* range, const String& directionString, ExceptionCode& ec)
188 {
189     LOG(IndexedDB, "IDBIndex::openKeyCursor");
190
191     if (m_deleted || m_objectStore->isDeleted()) {
192         ec = IDBDatabaseException::InvalidStateError;
193         return nullptr;
194     }
195
196     if (!m_objectStore->modernTransaction().isActive()) {
197         ec = IDBDatabaseException::TransactionInactiveError;
198         return nullptr;
199     }
200
201     IndexedDB::CursorDirection direction = IDBCursor::stringToDirection(directionString, ec);
202     if (ec)
203         return nullptr;
204
205     auto info = IDBCursorInfo::indexCursor(m_objectStore->modernTransaction(), m_info.identifier(), range, direction, IndexedDB::CursorType::KeyOnly);
206     Ref<IDBRequest> request = m_objectStore->modernTransaction().requestOpenCursor(*context, *this, info);
207     return WTF::move(request);
208 }
209
210 RefPtr<WebCore::IDBRequest> IDBIndex::openKeyCursor(ScriptExecutionContext* context, const Deprecated::ScriptValue& key, const String& direction, ExceptionCode& ec)
211 {
212     LOG(IndexedDB, "IDBIndex::openKeyCursor");
213     RefPtr<IDBKeyRange> keyRange = IDBKeyRange::only(context, key, ec);
214     if (ec)
215         return nullptr;
216
217     return openKeyCursor(context, keyRange.get(), direction, ec);
218 }
219
220 RefPtr<WebCore::IDBRequest> IDBIndex::get(ScriptExecutionContext* context, IDBKeyRange* range, ExceptionCode& ec)
221 {
222     LOG(IndexedDB, "IDBIndex::get");
223
224     if (!context) {
225         ec = INVALID_STATE_ERR;
226         return nullptr;
227     }
228
229     return doGet(*context, IDBKeyRangeData(range), ec);
230 }
231
232 RefPtr<WebCore::IDBRequest> IDBIndex::get(ScriptExecutionContext* context, const Deprecated::ScriptValue& key, ExceptionCode& ec)
233 {
234     LOG(IndexedDB, "IDBIndex::get");
235
236     if (!context) {
237         ec = INVALID_STATE_ERR;
238         return nullptr;
239     }
240
241     DOMRequestState requestState(context);
242     RefPtr<IDBKey> idbKey = scriptValueToIDBKey(&requestState, key);
243     if (!idbKey || idbKey->type() == KeyType::Invalid) {
244         ec = static_cast<ExceptionCode>(IDBExceptionCode::DataError);
245         return nullptr;
246     }
247
248     return doGet(*context, IDBKeyRangeData(idbKey.get()), ec);
249 }
250
251 RefPtr<WebCore::IDBRequest> IDBIndex::doGet(ScriptExecutionContext& context, const IDBKeyRangeData& range, ExceptionCode& ec)
252 {
253     if (m_deleted || m_objectStore->isDeleted()) {
254         ec = INVALID_STATE_ERR;
255         return nullptr;
256     }
257
258     if (range.isNull) {
259         ec = static_cast<ExceptionCode>(IDBExceptionCode::DataError);
260         return nullptr;
261     }
262
263     auto& transaction = m_objectStore->modernTransaction();
264     if (!transaction.isActive()) {
265         ec = static_cast<ExceptionCode>(IDBExceptionCode::TransactionInactiveError);
266         return nullptr;
267     }
268
269     return transaction.requestGetValue(context, *this, range);
270 }
271
272 RefPtr<WebCore::IDBRequest> IDBIndex::getKey(ScriptExecutionContext* context, IDBKeyRange* range, ExceptionCode& ec)
273 {
274     LOG(IndexedDB, "IDBIndex::getKey");
275
276     if (!context) {
277         ec = INVALID_STATE_ERR;
278         return nullptr;
279     }
280
281     return doGetKey(*context, IDBKeyRangeData(range), ec);
282 }
283
284 RefPtr<WebCore::IDBRequest> IDBIndex::getKey(ScriptExecutionContext* context, const Deprecated::ScriptValue& key, ExceptionCode& ec)
285 {
286     LOG(IndexedDB, "IDBIndex::getKey");
287
288     if (!context) {
289         ec = INVALID_STATE_ERR;
290         return nullptr;
291     }
292
293     DOMRequestState requestState(context);
294     RefPtr<IDBKey> idbKey = scriptValueToIDBKey(&requestState, key);
295     if (!idbKey || idbKey->type() == KeyType::Invalid) {
296         ec = static_cast<ExceptionCode>(IDBExceptionCode::DataError);
297         return nullptr;
298     }
299
300     return doGetKey(*context, IDBKeyRangeData(idbKey.get()), ec);
301 }
302
303 RefPtr<WebCore::IDBRequest> IDBIndex::doGetKey(ScriptExecutionContext& context, const IDBKeyRangeData& range, ExceptionCode& ec)
304 {
305     if (m_deleted || m_objectStore->isDeleted()) {
306         ec = INVALID_STATE_ERR;
307         return nullptr;
308     }
309
310     if (range.isNull) {
311         ec = static_cast<ExceptionCode>(IDBExceptionCode::DataError);
312         return nullptr;
313     }
314
315     auto& transaction = m_objectStore->modernTransaction();
316     if (!transaction.isActive()) {
317         ec = static_cast<ExceptionCode>(IDBExceptionCode::TransactionInactiveError);
318         return nullptr;
319     }
320
321     return transaction.requestGetKey(context, *this, range);
322 }
323
324 } // namespace IDBClient
325 } // namespace WebCore
326
327 #endif // ENABLE(INDEXED_DATABASE)