Replace WTF::move with WTFMove
[WebKit-https.git] / Source / WebCore / Modules / indexeddb / client / IDBObjectStoreImpl.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 "IDBObjectStoreImpl.h"
28
29 #if ENABLE(INDEXED_DATABASE)
30
31 #include "DOMRequestState.h"
32 #include "IDBBindingUtilities.h"
33 #include "IDBCursorImpl.h"
34 #include "IDBDatabaseException.h"
35 #include "IDBError.h"
36 #include "IDBIndexImpl.h"
37 #include "IDBKey.h"
38 #include "IDBKeyRangeData.h"
39 #include "IDBRequestImpl.h"
40 #include "IDBTransactionImpl.h"
41 #include "IndexedDB.h"
42 #include "Logging.h"
43 #include "SerializedScriptValue.h"
44
45 namespace WebCore {
46 namespace IDBClient {
47
48 Ref<IDBObjectStore> IDBObjectStore::create(const IDBObjectStoreInfo& info, IDBTransaction& transaction)
49 {
50     return adoptRef(*new IDBObjectStore(info, transaction));
51 }
52
53 IDBObjectStore::IDBObjectStore(const IDBObjectStoreInfo& info, IDBTransaction& transaction)
54     : m_info(info)
55     , m_originalInfo(info)
56     , m_transaction(transaction)
57 {
58 }
59
60 IDBObjectStore::~IDBObjectStore()
61 {
62 }
63
64 const String IDBObjectStore::name() const
65 {
66     return m_info.name();
67 }
68
69 RefPtr<WebCore::IDBAny> IDBObjectStore::keyPathAny() const
70 {
71     return IDBAny::create(m_info.keyPath());
72 }
73
74 const IDBKeyPath IDBObjectStore::keyPath() const
75 {
76     return m_info.keyPath();
77 }
78
79 RefPtr<DOMStringList> IDBObjectStore::indexNames() const
80 {
81     RefPtr<DOMStringList> indexNames = DOMStringList::create();
82     for (auto& name : m_info.indexNames())
83         indexNames->append(name);
84     indexNames->sort();
85
86     return indexNames;
87 }
88
89 RefPtr<WebCore::IDBTransaction> IDBObjectStore::transaction()
90 {
91     return &m_transaction.get();
92 }
93
94 bool IDBObjectStore::autoIncrement() const
95 {
96     return m_info.autoIncrement();
97 }
98
99 RefPtr<WebCore::IDBRequest> IDBObjectStore::openCursor(ScriptExecutionContext* context, ExceptionCodeWithMessage& ec)
100 {
101     return openCursor(context, static_cast<IDBKeyRange*>(nullptr), ec);
102 }
103
104 RefPtr<WebCore::IDBRequest> IDBObjectStore::openCursor(ScriptExecutionContext* context, IDBKeyRange* keyRange, ExceptionCodeWithMessage& ec)
105 {
106     return openCursor(context, keyRange, IDBCursor::directionNext(), ec);
107 }
108
109 RefPtr<WebCore::IDBRequest> IDBObjectStore::openCursor(ScriptExecutionContext* context, const Deprecated::ScriptValue& key, ExceptionCodeWithMessage& ec)
110 {
111     return openCursor(context, key, IDBCursor::directionNext(), ec);
112 }
113
114 RefPtr<WebCore::IDBRequest> IDBObjectStore::openCursor(ScriptExecutionContext* context, IDBKeyRange* range, const String& directionString, ExceptionCodeWithMessage& ec)
115 {
116     LOG(IndexedDB, "IDBObjectStore::openCursor");
117
118     if (m_deleted) {
119         ec.code = IDBDatabaseException::InvalidStateError;
120         return nullptr;
121     }
122
123     if (!m_transaction->isActive()) {
124         ec.code = IDBDatabaseException::TransactionInactiveError;
125         ec.message = ASCIILiteral("Failed to execute 'openCursor' on 'IDBObjectStore': The transaction is inactive or finished.");
126         return nullptr;
127     }
128
129     IndexedDB::CursorDirection direction = IDBCursor::stringToDirection(directionString, ec.code);
130     if (ec.code)
131         return nullptr;
132
133     auto info = IDBCursorInfo::objectStoreCursor(m_transaction.get(), m_info.identifier(), range, direction);
134     Ref<IDBRequest> request = m_transaction->requestOpenCursor(*context, *this, info);
135     return WTFMove(request);
136 }
137
138 RefPtr<WebCore::IDBRequest> IDBObjectStore::openCursor(ScriptExecutionContext* context, const Deprecated::ScriptValue& key, const String& direction, ExceptionCodeWithMessage& ec)
139 {
140     RefPtr<IDBKeyRange> keyRange = IDBKeyRange::only(context, key, ec.code);
141     if (ec.code) {
142         ec.message = ASCIILiteral("Failed to execute 'openCursor' on 'IDBObjectStore': The parameter is not a valid key.");
143         return 0;
144     }
145
146     return openCursor(context, keyRange.get(), direction, ec);
147 }
148
149 RefPtr<WebCore::IDBRequest> IDBObjectStore::get(ScriptExecutionContext* context, const Deprecated::ScriptValue& key, ExceptionCodeWithMessage& ec)
150 {
151     LOG(IndexedDB, "IDBObjectStore::get");
152
153     if (!context) {
154         ec.code = IDBDatabaseException::InvalidStateError;
155         return nullptr;
156     }
157
158     if (!m_transaction->isActive()) {
159         ec.code = IDBDatabaseException::TransactionInactiveError;
160         ec.message = ASCIILiteral("Failed to execute 'get' on 'IDBObjectStore': The transaction is inactive or finished.");
161         return nullptr;
162     }
163
164     if (m_deleted) {
165         ec.code = IDBDatabaseException::InvalidStateError;
166         return nullptr;
167     }
168
169     DOMRequestState requestState(context);
170     RefPtr<IDBKey> idbKey = scriptValueToIDBKey(&requestState, key);
171     if (!idbKey || idbKey->type() == KeyType::Invalid) {
172         ec.code = IDBDatabaseException::DataError;
173         ec.message = ASCIILiteral("Failed to execute 'get' on 'IDBObjectStore': The parameter is not a valid key.");
174         return nullptr;
175     }
176
177     Ref<IDBRequest> request = m_transaction->requestGetRecord(*context, *this, idbKey.get());
178     return WTFMove(request);
179 }
180
181 RefPtr<WebCore::IDBRequest> IDBObjectStore::get(ScriptExecutionContext* context, IDBKeyRange* keyRange, ExceptionCodeWithMessage& ec)
182 {
183     LOG(IndexedDB, "IDBObjectStore::get");
184
185     if (!context) {
186         ec.code = IDBDatabaseException::InvalidStateError;
187         return nullptr;
188     }
189
190     if (!m_transaction->isActive()) {
191         ec.code = IDBDatabaseException::TransactionInactiveError;
192         return nullptr;
193     }
194
195     if (m_deleted) {
196         ec.code = IDBDatabaseException::InvalidStateError;
197         return nullptr;
198     }
199
200     IDBKeyRangeData keyRangeData(keyRange);
201     if (!keyRangeData.isValid()) {
202         ec.code = IDBDatabaseException::DataError;
203         return nullptr;
204     }
205
206     Ref<IDBRequest> request = m_transaction->requestGetRecord(*context, *this, keyRangeData);
207     return WTFMove(request);
208 }
209
210 RefPtr<WebCore::IDBRequest> IDBObjectStore::add(JSC::ExecState& state, JSC::JSValue value, ExceptionCodeWithMessage& ec)
211 {
212     return putOrAdd(state, value, nullptr, IndexedDB::ObjectStoreOverwriteMode::NoOverwrite, InlineKeyCheck::Perform, ec);
213 }
214
215 RefPtr<WebCore::IDBRequest> IDBObjectStore::add(JSC::ExecState& execState, JSC::JSValue value, JSC::JSValue key, ExceptionCodeWithMessage& ec)
216 {
217     RefPtr<IDBKey> idbKey;
218     if (!key.isUndefined())
219         idbKey = scriptValueToIDBKey(execState, key);
220     return putOrAdd(execState, value, idbKey, IndexedDB::ObjectStoreOverwriteMode::NoOverwrite, InlineKeyCheck::Perform, ec);
221 }
222
223 RefPtr<WebCore::IDBRequest> IDBObjectStore::put(JSC::ExecState& execState, JSC::JSValue value, JSC::JSValue key, ExceptionCodeWithMessage& ec)
224 {
225     RefPtr<IDBKey> idbKey;
226     if (!key.isUndefined())
227         idbKey = scriptValueToIDBKey(execState, key);
228     return putOrAdd(execState, value, idbKey, IndexedDB::ObjectStoreOverwriteMode::Overwrite, InlineKeyCheck::Perform, ec);
229 }
230
231 RefPtr<WebCore::IDBRequest> IDBObjectStore::put(JSC::ExecState& state, JSC::JSValue value, ExceptionCodeWithMessage& ec)
232 {
233     return putOrAdd(state, value, nullptr, IndexedDB::ObjectStoreOverwriteMode::Overwrite, InlineKeyCheck::Perform, ec);
234 }
235
236 RefPtr<IDBRequest> IDBObjectStore::putForCursorUpdate(JSC::ExecState& state, JSC::JSValue value, JSC::JSValue key, ExceptionCodeWithMessage& ec)
237 {
238     return putOrAdd(state, value, scriptValueToIDBKey(state, key), IndexedDB::ObjectStoreOverwriteMode::OverwriteForCursor, InlineKeyCheck::DoNotPerform, ec);
239 }
240
241 RefPtr<IDBRequest> IDBObjectStore::putOrAdd(JSC::ExecState& state, JSC::JSValue value, RefPtr<IDBKey> key, IndexedDB::ObjectStoreOverwriteMode overwriteMode, InlineKeyCheck inlineKeyCheck, ExceptionCodeWithMessage& ec)
242 {
243     LOG(IndexedDB, "IDBObjectStore::putOrAdd");
244
245     if (!m_transaction->isActive()) {
246         ec.code = IDBDatabaseException::TransactionInactiveError;
247         ec.message = ASCIILiteral("Failed to store record in an IDBObjectStore: The transaction is inactive or finished.");
248         return nullptr;
249     }
250
251     if (m_transaction->isReadOnly()) {
252         ec.code = IDBDatabaseException::ReadOnlyError;
253         ec.message = ASCIILiteral("Failed to store record in an IDBObjectStore: The transaction is read-only.");
254         return nullptr;
255     }
256
257     if (m_deleted) {
258         ec.code = IDBDatabaseException::InvalidStateError;
259         return nullptr;
260     }
261
262     RefPtr<SerializedScriptValue> serializedValue = SerializedScriptValue::create(&state, value, nullptr, nullptr);
263     if (state.hadException()) {
264         ec.code = IDBDatabaseException::DataCloneError;
265         ec.message = ASCIILiteral("Failed to store record in an IDBObjectStore: An object could not be cloned.");
266         return nullptr;
267     }
268
269     if (serializedValue->hasBlobURLs()) {
270         // FIXME: Add Blob/File/FileList support
271         ec.code = IDBDatabaseException::DataCloneError;
272         ec.message = ASCIILiteral("Failed to store record in an IDBObjectStore: BlobURLs are not yet supported.");
273         return nullptr;
274     }
275
276     if (key && !key->isValid()) {
277         ec.code = IDBDatabaseException::DataError;
278         ec.message = ASCIILiteral("Failed to store record in an IDBObjectStore: The parameter is not a valid key.");
279         return nullptr;
280     }
281
282     bool usesInlineKeys = !m_info.keyPath().isNull();
283     bool usesKeyGenerator = autoIncrement();
284     if (usesInlineKeys && inlineKeyCheck == InlineKeyCheck::Perform) {
285         if (key) {
286             ec.code = IDBDatabaseException::DataError;
287             ec.message = ASCIILiteral("Failed to store record in an IDBObjectStore: The object store uses in-line keys and the key parameter was provided.");
288             return nullptr;
289         }
290
291         RefPtr<IDBKey> keyPathKey = maybeCreateIDBKeyFromScriptValueAndKeyPath(state, value, m_info.keyPath());
292         if (keyPathKey && !keyPathKey->isValid()) {
293             ec.code = IDBDatabaseException::DataError;
294             ec.message = ASCIILiteral("Failed to store record in an IDBObjectStore: Evaluating the object store's key path yielded a value that is not a valid key.");
295             return nullptr;
296         }
297
298         if (!keyPathKey) {
299             if (usesKeyGenerator) {
300                 if (!canInjectIDBKeyIntoScriptValue(state, value, m_info.keyPath())) {
301                     ec.code = IDBDatabaseException::DataError;
302                     return nullptr;
303                 }
304             } else {
305                 ec.code = IDBDatabaseException::DataError;
306                 ec.message = ASCIILiteral("Failed to store record in an IDBObjectStore: Evaluating the object store's key path did not yield a value.");
307                 return nullptr;
308             }
309         }
310
311         if (keyPathKey) {
312             ASSERT(!key);
313             key = keyPathKey;
314         }
315     } else if (!usesKeyGenerator && !key) {
316         ec.code = IDBDatabaseException::DataError;
317         ec.message = ASCIILiteral("Failed to store record in an IDBObjectStore: The object store uses out-of-line keys and has no key generator and the key parameter was not provided.");
318         return nullptr;
319     }
320
321     auto context = scriptExecutionContextFromExecState(&state);
322     if (!context) {
323         ec.code = IDBDatabaseException::UnknownError;
324         return nullptr;
325     }
326
327     Ref<IDBRequest> request = m_transaction->requestPutOrAdd(*context, *this, key.get(), *serializedValue, overwriteMode);
328     return adoptRef(request.leakRef());
329 }
330
331
332 RefPtr<WebCore::IDBRequest> IDBObjectStore::deleteFunction(ScriptExecutionContext* context, IDBKeyRange* keyRange, ExceptionCodeWithMessage& ec)
333 {
334     LOG(IndexedDB, "IDBObjectStore::deleteFunction");
335
336     if (!m_transaction->isActive()) {
337         ec.code = IDBDatabaseException::TransactionInactiveError;
338         ec.message = ASCIILiteral("Failed to execute 'delete' on 'IDBObjectStore': The transaction is inactive or finished.");
339         return nullptr;
340     }
341
342     if (m_transaction->isReadOnly()) {
343         ec.code = IDBDatabaseException::ReadOnlyError;
344         ec.message = ASCIILiteral("Failed to execute 'delete' on 'IDBObjectStore': The transaction is read-only.");
345         return nullptr;
346     }
347
348     if (m_deleted) {
349         ec.code = IDBDatabaseException::InvalidStateError;
350         return nullptr;
351     }
352
353     IDBKeyRangeData keyRangeData(keyRange);
354     if (!keyRangeData.isValid()) {
355         ec.code = IDBDatabaseException::DataError;
356         ec.message = ASCIILiteral("Failed to execute 'delete' on 'IDBObjectStore': The parameter is not a valid key range.");
357         return nullptr;
358     }
359
360     Ref<IDBRequest> request = m_transaction->requestDeleteRecord(*context, *this, keyRangeData);
361     return WTFMove(request);
362 }
363
364 RefPtr<WebCore::IDBRequest> IDBObjectStore::deleteFunction(ScriptExecutionContext* context, const Deprecated::ScriptValue& key, ExceptionCodeWithMessage& ec)
365 {
366     return deleteFunction(context, key.jsValue(), ec);
367 }
368
369 RefPtr<WebCore::IDBRequest> IDBObjectStore::deleteFunction(ScriptExecutionContext* context, JSC::JSValue key, ExceptionCodeWithMessage& ec)
370 {
371     DOMRequestState requestState(context);
372     RefPtr<IDBKey> idbKey = scriptValueToIDBKey(&requestState, key);
373     if (!idbKey || idbKey->type() == KeyType::Invalid) {
374         ec.code = IDBDatabaseException::DataError;
375         ec.message = ASCIILiteral("Failed to execute 'delete' on 'IDBObjectStore': The parameter is not a valid key.");
376         return nullptr;
377     }
378
379     return deleteFunction(context, &IDBKeyRange::create(idbKey.get()).get(), ec);
380 }
381
382 RefPtr<WebCore::IDBRequest> IDBObjectStore::clear(ScriptExecutionContext* context, ExceptionCodeWithMessage& ec)
383 {
384     LOG(IndexedDB, "IDBObjectStore::clear");
385
386     if (!m_transaction->isActive()) {
387         ec.code = IDBDatabaseException::TransactionInactiveError;
388         ec.message = ASCIILiteral("Failed to execute 'clear' on 'IDBObjectStore': The transaction is inactive or finished.");
389         return nullptr;
390     }
391
392     if (m_transaction->isReadOnly()) {
393         ec.code = IDBDatabaseException::ReadOnlyError;
394         ec.message = ASCIILiteral("Failed to execute 'clear' on 'IDBObjectStore': The transaction is read-only.");
395         return nullptr;
396     }
397
398     if (m_deleted) {
399         ec.code = IDBDatabaseException::InvalidStateError;
400         return nullptr;
401     }
402
403     Ref<IDBRequest> request = m_transaction->requestClearObjectStore(*context, *this);
404     return adoptRef(request.leakRef());
405 }
406
407 RefPtr<WebCore::IDBIndex> IDBObjectStore::createIndex(ScriptExecutionContext* context, const String& name, const IDBKeyPath& keyPath, bool unique, bool multiEntry, ExceptionCodeWithMessage& ec)
408 {
409     LOG(IndexedDB, "IDBObjectStore::createIndex %s", name.utf8().data());
410
411     if (!context) {
412         ec.code = IDBDatabaseException::InvalidStateError;
413         return nullptr;
414     }
415
416     if (m_deleted) {
417         ec.code = IDBDatabaseException::InvalidStateError;
418         return nullptr;
419     }
420
421     if (!m_transaction->isVersionChange()) {
422         ec.code = IDBDatabaseException::InvalidStateError;
423         ec.message = ASCIILiteral("Failed to execute 'createIndex' on 'IDBObjectStore': The database is not running a version change transaction.");
424         return nullptr;
425     }
426
427     if (!m_transaction->isActive()) {
428         ec.code = IDBDatabaseException::TransactionInactiveError;
429         return nullptr;
430     }
431
432     if (!keyPath.isValid()) {
433         ec.code = IDBDatabaseException::SyntaxError;
434         ec.message = ASCIILiteral("Failed to execute 'createIndex' on 'IDBObjectStore': The keyPath argument contains an invalid key path.");
435         return nullptr;
436     }
437
438     if (name.isNull()) {
439         ec.code = TypeError;
440         return nullptr;
441     }
442
443     if (m_info.hasIndex(name)) {
444         ec.code = IDBDatabaseException::ConstraintError;
445         ec.message = ASCIILiteral("Failed to execute 'createIndex' on 'IDBObjectStore': An index with the specified name already exists.");
446         return nullptr;
447     }
448
449     if (keyPath.type() == IndexedDB::KeyPathType::Array && multiEntry) {
450         ec.code = IDBDatabaseException::InvalidAccessError;
451         ec.message = ASCIILiteral("Failed to execute 'createIndex' on 'IDBObjectStore': The keyPath argument was an array and the multiEntry option is true.");
452         return nullptr;
453     }
454
455     // Install the new Index into the ObjectStore's info.
456     IDBIndexInfo info = m_info.createNewIndex(name, keyPath, unique, multiEntry);
457     m_transaction->database().didCreateIndexInfo(info);
458
459     // Create the actual IDBObjectStore from the transaction, which also schedules the operation server side.
460     Ref<IDBIndex> index = m_transaction->createIndex(*this, info);
461     m_referencedIndexes.set(name, &index.get());
462
463     return WTFMove(index);
464 }
465
466 RefPtr<WebCore::IDBIndex> IDBObjectStore::index(const String& indexName, ExceptionCodeWithMessage& ec)
467 {
468     LOG(IndexedDB, "IDBObjectStore::index");
469
470     if (m_deleted) {
471         ec.code = IDBDatabaseException::InvalidStateError;
472         return nullptr;
473     }
474
475     if (m_transaction->isFinishedOrFinishing()) {
476         ec.code = IDBDatabaseException::InvalidStateError;
477         ec.message = ASCIILiteral("Failed to execute 'index' on 'IDBObjectStore': The transaction is finished.");
478         return nullptr;
479     }
480
481     auto iterator = m_referencedIndexes.find(indexName);
482     if (iterator != m_referencedIndexes.end())
483         return iterator->value;
484
485     auto* info = m_info.infoForExistingIndex(indexName);
486     if (!info) {
487         ec.code = IDBDatabaseException::NotFoundError;
488         ec.message = ASCIILiteral("Failed to execute 'index' on 'IDBObjectStore': The specified index was not found.");
489         return nullptr;
490     }
491
492     auto index = IDBIndex::create(*info, *this);
493     m_referencedIndexes.set(indexName, &index.get());
494
495     return WTFMove(index);
496 }
497
498 void IDBObjectStore::deleteIndex(const String& name, ExceptionCodeWithMessage& ec)
499 {
500     LOG(IndexedDB, "IDBObjectStore::deleteIndex %s", name.utf8().data());
501
502     if (m_deleted) {
503         ec.code = IDBDatabaseException::InvalidStateError;
504         return;
505     }
506
507     if (!m_transaction->isVersionChange()) {
508         ec.code = IDBDatabaseException::InvalidStateError;
509         ec.message = ASCIILiteral("Failed to execute 'deleteIndex' on 'IDBObjectStore': The database is not running a version change transaction.");
510         return;
511     }
512
513     if (!m_transaction->isActive()) {
514         ec.code = IDBDatabaseException::TransactionInactiveError;
515         ec.message = ASCIILiteral("Failed to execute 'deleteIndex' on 'IDBObjectStore': The transaction is inactive or finished.");
516         return;
517     }
518
519     if (!m_info.hasIndex(name)) {
520         ec.code = IDBDatabaseException::NotFoundError;
521         ec.message = ASCIILiteral("Failed to execute 'deleteIndex' on 'IDBObjectStore': The specified index was not found.");
522         return;
523     }
524
525     auto* info = m_info.infoForExistingIndex(name);
526     ASSERT(info);
527     m_transaction->database().didDeleteIndexInfo(*info);
528
529     m_info.deleteIndex(name);
530
531     if (auto index = m_referencedIndexes.take(name))
532         index->markAsDeleted();
533
534     m_transaction->deleteIndex(m_info.identifier(), name);
535 }
536
537 RefPtr<WebCore::IDBRequest> IDBObjectStore::count(ScriptExecutionContext* context, ExceptionCodeWithMessage& ec)
538 {
539     LOG(IndexedDB, "IDBObjectStore::count");
540
541     if (!context) {
542         ec.code = IDBDatabaseException::InvalidStateError;
543         return nullptr;
544     }
545
546     return doCount(*context, IDBKeyRangeData::allKeys(), ec);
547 }
548
549 RefPtr<WebCore::IDBRequest> IDBObjectStore::count(ScriptExecutionContext* context, const Deprecated::ScriptValue& key, ExceptionCodeWithMessage& ec)
550 {
551     LOG(IndexedDB, "IDBObjectStore::count");
552
553     if (!context) {
554         ec.code = IDBDatabaseException::InvalidStateError;
555         return nullptr;
556     }
557
558     DOMRequestState requestState(context);
559     RefPtr<IDBKey> idbKey = scriptValueToIDBKey(&requestState, key);
560     if (!idbKey || idbKey->type() == KeyType::Invalid) {
561         ec.code = IDBDatabaseException::DataError;
562         ec.message = ASCIILiteral("Failed to execute 'count' on 'IDBObjectStore': The parameter is not a valid key.");
563         return nullptr;
564     }
565
566     return doCount(*context, IDBKeyRangeData(idbKey.get()), ec);
567 }
568
569 RefPtr<WebCore::IDBRequest> IDBObjectStore::count(ScriptExecutionContext* context, IDBKeyRange* range, ExceptionCodeWithMessage& ec)
570 {
571     LOG(IndexedDB, "IDBObjectStore::count");
572
573     if (!context) {
574         ec.code = IDBDatabaseException::InvalidStateError;
575         return nullptr;
576     }
577
578     return doCount(*context, range ? IDBKeyRangeData(range) : IDBKeyRangeData::allKeys(), ec);
579 }
580
581 RefPtr<WebCore::IDBRequest> IDBObjectStore::doCount(ScriptExecutionContext& context, const IDBKeyRangeData& range, ExceptionCodeWithMessage& ec)
582 {
583     if (!m_transaction->isActive()) {
584         ec.code = IDBDatabaseException::TransactionInactiveError;
585         ec.message = ASCIILiteral("Failed to execute 'count' on 'IDBObjectStore': The transaction is inactive or finished.");
586         return nullptr;
587     }
588
589     if (m_deleted) {
590         ec.code = IDBDatabaseException::InvalidStateError;
591         return nullptr;
592     }
593
594     if (!range.isValid()) {
595         ec.code = IDBDatabaseException::DataError;
596         return nullptr;
597     }
598
599     return m_transaction->requestCount(context, *this, range);
600 }
601
602 void IDBObjectStore::markAsDeleted()
603 {
604     m_deleted = true;
605 }
606
607 void IDBObjectStore::rollbackInfoForVersionChangeAbort()
608 {
609     m_info = m_originalInfo;
610 }
611
612 } // namespace IDBClient
613 } // namespace WebCore
614
615 #endif // ENABLE(INDEXED_DATABASE)