Replace WTF::move with WTFMove
[WebKit-https.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, ExceptionCodeWithMessage& ec)
90 {
91     LOG(IndexedDB, "IDBIndex::openCursor");
92
93     if (m_deleted || m_objectStore->isDeleted()) {
94         ec.code = IDBDatabaseException::InvalidStateError;
95         return nullptr;
96     }
97
98     if (!m_objectStore->modernTransaction().isActive()) {
99         ec.code = IDBDatabaseException::TransactionInactiveError;
100         ec.message = ASCIILiteral("Failed to execute 'openCursor' on 'IDBIndex': The transaction is inactive or finished.");
101         return nullptr;
102     }
103
104     IndexedDB::CursorDirection direction = IDBCursor::stringToDirection(directionString, ec.code);
105     if (ec.code) {
106         ec.message = ASCIILiteral("Failed to execute 'openCursor' on 'IDBIndex': The direction provided ('invalid-direction') is not one of 'next', 'nextunique', 'prev', or 'prevunique'.");
107         return nullptr;
108     }
109
110     IDBKeyRangeData rangeData = range;
111     if (rangeData.lowerKey.isNull())
112         rangeData.lowerKey = IDBKeyData::minimum();
113     if (rangeData.upperKey.isNull())
114         rangeData.upperKey = IDBKeyData::maximum();
115
116     auto info = IDBCursorInfo::indexCursor(m_objectStore->modernTransaction(), m_objectStore->info().identifier(), m_info.identifier(), rangeData, direction, IndexedDB::CursorType::KeyAndValue);
117     Ref<IDBRequest> request = m_objectStore->modernTransaction().requestOpenCursor(*context, *this, info);
118     return WTFMove(request);
119 }
120
121 RefPtr<WebCore::IDBRequest> IDBIndex::openCursor(ScriptExecutionContext* context, const Deprecated::ScriptValue& key, const String& direction, ExceptionCodeWithMessage& ec)
122 {
123     LOG(IndexedDB, "IDBIndex::openCursor");
124     RefPtr<IDBKeyRange> keyRange = IDBKeyRange::only(context, key, ec.code);
125     if (ec.code) {
126         ec.message = ASCIILiteral("Failed to execute 'openCursor' on 'IDBIndex': The parameter is not a valid key.");
127         return nullptr;
128     }
129
130     return openCursor(context, keyRange.get(), direction, ec);
131 }
132
133 RefPtr<WebCore::IDBRequest> IDBIndex::count(ScriptExecutionContext* context, ExceptionCodeWithMessage& ec)
134 {
135     LOG(IndexedDB, "IDBIndex::count");
136
137     if (!context) {
138         ec.code = IDBDatabaseException::InvalidStateError;
139         return nullptr;
140     }
141
142     return doCount(*context, IDBKeyRangeData::allKeys(), ec);
143 }
144
145 RefPtr<WebCore::IDBRequest> IDBIndex::count(ScriptExecutionContext* context, IDBKeyRange* range, ExceptionCodeWithMessage& ec)
146 {
147     LOG(IndexedDB, "IDBIndex::count");
148
149     if (!context) {
150         ec.code = IDBDatabaseException::InvalidStateError;
151         return nullptr;
152     }
153
154     return doCount(*context, range ? IDBKeyRangeData(range) : IDBKeyRangeData::allKeys(), ec);
155 }
156
157 RefPtr<WebCore::IDBRequest> IDBIndex::count(ScriptExecutionContext* context, const Deprecated::ScriptValue& key, ExceptionCodeWithMessage& ec)
158 {
159     LOG(IndexedDB, "IDBIndex::count");
160
161     if (!context) {
162         ec.code = IDBDatabaseException::InvalidStateError;
163         return nullptr;
164     }
165
166     DOMRequestState requestState(context);
167     RefPtr<IDBKey> idbKey = scriptValueToIDBKey(&requestState, key);
168     if (!idbKey || idbKey->type() == KeyType::Invalid) {
169         ec.code = IDBDatabaseException::DataError;
170         ec.message = ASCIILiteral("Failed to execute 'count' on 'IDBIndex': The parameter is not a valid key.");
171         return nullptr;
172     }
173
174     return doCount(*context, IDBKeyRangeData(idbKey.get()), ec);
175 }
176
177 RefPtr<WebCore::IDBRequest> IDBIndex::doCount(ScriptExecutionContext& context, const IDBKeyRangeData& range, ExceptionCodeWithMessage& ec)
178 {
179     if (m_deleted || m_objectStore->isDeleted()) {
180         ec.code = IDBDatabaseException::InvalidStateError;
181         return nullptr;
182     }
183
184     if (!range.isValid()) {
185         ec.code = IDBDatabaseException::DataError;
186         return nullptr;
187     }
188
189     auto& transaction = m_objectStore->modernTransaction();
190     if (!transaction.isActive()) {
191         ec.code = IDBDatabaseException::TransactionInactiveError;
192         ec.message = ASCIILiteral("Failed to execute 'count' on 'IDBIndex': The transaction is inactive or finished.");
193         return nullptr;
194     }
195
196     return transaction.requestCount(context, *this, range);
197 }
198
199 RefPtr<WebCore::IDBRequest> IDBIndex::openKeyCursor(ScriptExecutionContext* context, IDBKeyRange* range, const String& directionString, ExceptionCodeWithMessage& ec)
200 {
201     LOG(IndexedDB, "IDBIndex::openKeyCursor");
202
203     if (m_deleted || m_objectStore->isDeleted()) {
204         ec.code = IDBDatabaseException::InvalidStateError;
205         return nullptr;
206     }
207
208     if (!m_objectStore->modernTransaction().isActive()) {
209         ec.code = IDBDatabaseException::TransactionInactiveError;
210         ec.message = ASCIILiteral("Failed to execute 'openKeyCursor' on 'IDBIndex': The transaction is inactive or finished.");
211         return nullptr;
212     }
213
214     IndexedDB::CursorDirection direction = IDBCursor::stringToDirection(directionString, ec.code);
215     if (ec.code) {
216         ec.message = ASCIILiteral("Failed to execute 'openKeyCursor' on 'IDBIndex': The direction provided ('invalid-direction') is not one of 'next', 'nextunique', 'prev', or 'prevunique'.");
217         return nullptr;
218     }
219
220     auto info = IDBCursorInfo::indexCursor(m_objectStore->modernTransaction(), m_objectStore->info().identifier(), m_info.identifier(), range, direction, IndexedDB::CursorType::KeyOnly);
221     Ref<IDBRequest> request = m_objectStore->modernTransaction().requestOpenCursor(*context, *this, info);
222     return WTFMove(request);
223 }
224
225 RefPtr<WebCore::IDBRequest> IDBIndex::openKeyCursor(ScriptExecutionContext* context, const Deprecated::ScriptValue& key, const String& direction, ExceptionCodeWithMessage& ec)
226 {
227     LOG(IndexedDB, "IDBIndex::openKeyCursor");
228     RefPtr<IDBKeyRange> keyRange = IDBKeyRange::only(context, key, ec.code);
229     if (ec.code) {
230         ec.message = ASCIILiteral("Failed to execute 'openKeyCursor' on 'IDBIndex': The parameter is not a valid key.");
231         return nullptr;
232     }
233     return openKeyCursor(context, keyRange.get(), direction, ec);
234 }
235
236 RefPtr<WebCore::IDBRequest> IDBIndex::get(ScriptExecutionContext* context, IDBKeyRange* range, ExceptionCodeWithMessage& ec)
237 {
238     LOG(IndexedDB, "IDBIndex::get");
239
240     if (!context) {
241         ec.code = IDBDatabaseException::InvalidStateError;
242         return nullptr;
243     }
244
245     return doGet(*context, IDBKeyRangeData(range), ec);
246 }
247
248 RefPtr<WebCore::IDBRequest> IDBIndex::get(ScriptExecutionContext* context, const Deprecated::ScriptValue& key, ExceptionCodeWithMessage& ec)
249 {
250     LOG(IndexedDB, "IDBIndex::get");
251
252     if (!context) {
253         ec.code = IDBDatabaseException::InvalidStateError;
254         return nullptr;
255     }
256
257     DOMRequestState requestState(context);
258     RefPtr<IDBKey> idbKey = scriptValueToIDBKey(&requestState, key);
259     if (!idbKey || idbKey->type() == KeyType::Invalid) {
260         ec.code = IDBDatabaseException::DataError;
261         ec.message = ASCIILiteral("Failed to execute 'get' on 'IDBIndex': The parameter is not a valid key.");
262         return nullptr;
263     }
264
265     return doGet(*context, IDBKeyRangeData(idbKey.get()), ec);
266 }
267
268 RefPtr<WebCore::IDBRequest> IDBIndex::doGet(ScriptExecutionContext& context, const IDBKeyRangeData& range, ExceptionCodeWithMessage& ec)
269 {
270     if (m_deleted || m_objectStore->isDeleted()) {
271         ec.code = IDBDatabaseException::InvalidStateError;
272         return nullptr;
273     }
274
275     if (range.isNull) {
276         ec.code = IDBDatabaseException::DataError;
277         return nullptr;
278     }
279
280     auto& transaction = m_objectStore->modernTransaction();
281     if (!transaction.isActive()) {
282         ec.code = IDBDatabaseException::TransactionInactiveError;
283         ec.message = ASCIILiteral("Failed to execute 'get' on 'IDBIndex': The transaction is inactive or finished.");
284         return nullptr;
285     }
286
287     return transaction.requestGetValue(context, *this, range);
288 }
289
290 RefPtr<WebCore::IDBRequest> IDBIndex::getKey(ScriptExecutionContext* context, IDBKeyRange* range, ExceptionCodeWithMessage& ec)
291 {
292     LOG(IndexedDB, "IDBIndex::getKey");
293
294     if (!context) {
295         ec.code = IDBDatabaseException::InvalidStateError;
296         return nullptr;
297     }
298
299     return doGetKey(*context, IDBKeyRangeData(range), ec);
300 }
301
302 RefPtr<WebCore::IDBRequest> IDBIndex::getKey(ScriptExecutionContext* context, const Deprecated::ScriptValue& key, ExceptionCodeWithMessage& ec)
303 {
304     LOG(IndexedDB, "IDBIndex::getKey");
305
306     if (!context) {
307         ec.code = IDBDatabaseException::InvalidStateError;
308         return nullptr;
309     }
310
311     DOMRequestState requestState(context);
312     RefPtr<IDBKey> idbKey = scriptValueToIDBKey(&requestState, key);
313     if (!idbKey || idbKey->type() == KeyType::Invalid) {
314         ec.code = IDBDatabaseException::DataError;
315         ec.message = ASCIILiteral("Failed to execute 'getKey' on 'IDBIndex': The parameter is not a valid key.");
316         return nullptr;
317     }
318
319     return doGetKey(*context, IDBKeyRangeData(idbKey.get()), ec);
320 }
321
322 RefPtr<WebCore::IDBRequest> IDBIndex::doGetKey(ScriptExecutionContext& context, const IDBKeyRangeData& range, ExceptionCodeWithMessage& ec)
323 {
324     if (m_deleted || m_objectStore->isDeleted()) {
325         ec.code = IDBDatabaseException::InvalidStateError;
326         return nullptr;
327     }
328
329     if (range.isNull) {
330         ec.code = IDBDatabaseException::DataError;
331         return nullptr;
332     }
333
334     auto& transaction = m_objectStore->modernTransaction();
335     if (!transaction.isActive()) {
336         ec.code = IDBDatabaseException::TransactionInactiveError;
337         ec.message = ASCIILiteral("Failed to execute 'getKey' on 'IDBIndex': The transaction is inactive or finished.");
338         return nullptr;
339     }
340
341     return transaction.requestGetKey(context, *this, range);
342 }
343
344 void IDBIndex::markAsDeleted()
345 {
346     m_deleted = true;
347 }
348
349 } // namespace IDBClient
350 } // namespace WebCore
351
352 #endif // ENABLE(INDEXED_DATABASE)