Modern IDB: Pipe through cursor functions from client to server.
[WebKit-https.git] / Source / WebCore / Modules / indexeddb / client / IDBTransactionImpl.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 "IDBTransactionImpl.h"
28
29 #if ENABLE(INDEXED_DATABASE)
30
31 #include "DOMError.h"
32 #include "EventQueue.h"
33 #include "IDBCursorWithValueImpl.h"
34 #include "IDBDatabaseImpl.h"
35 #include "IDBError.h"
36 #include "IDBEventDispatcher.h"
37 #include "IDBKeyData.h"
38 #include "IDBKeyRangeData.h"
39 #include "IDBObjectStore.h"
40 #include "IDBRequestImpl.h"
41 #include "IDBResultData.h"
42 #include "JSDOMWindowBase.h"
43 #include "Logging.h"
44 #include "ScriptExecutionContext.h"
45 #include "TransactionOperation.h"
46
47 namespace WebCore {
48 namespace IDBClient {
49
50 Ref<IDBTransaction> IDBTransaction::create(IDBDatabase& database, const IDBTransactionInfo& info)
51 {
52     return adoptRef(*new IDBTransaction(database, info));
53 }
54
55 IDBTransaction::IDBTransaction(IDBDatabase& database, const IDBTransactionInfo& info)
56     : WebCore::IDBTransaction(database.scriptExecutionContext())
57     , m_database(database)
58     , m_info(info)
59     , m_operationTimer(*this, &IDBTransaction::operationTimerFired)
60
61 {
62     relaxAdoptionRequirement();
63
64     if (m_info.mode() == IndexedDB::TransactionMode::VersionChange) {
65         m_originalDatabaseInfo = std::make_unique<IDBDatabaseInfo>(m_database->info());
66         m_startedOnServer = true;
67     } else {
68         activate();
69
70         RefPtr<IDBTransaction> self;
71         JSC::VM& vm = JSDOMWindowBase::commonVM();
72         vm.whenIdle([self, this]() {
73             deactivate();
74         });
75
76         establishOnServer();
77     }
78
79     suspendIfNeeded();
80 }
81
82 IDBTransaction::~IDBTransaction()
83 {
84 }
85
86 const String& IDBTransaction::mode() const
87 {
88     switch (m_info.mode()) {
89     case IndexedDB::TransactionMode::ReadOnly:
90         return IDBTransaction::modeReadOnly();
91     case IndexedDB::TransactionMode::ReadWrite:
92         return IDBTransaction::modeReadWrite();
93     case IndexedDB::TransactionMode::VersionChange:
94         return IDBTransaction::modeVersionChange();
95     }
96
97     RELEASE_ASSERT_NOT_REACHED();
98 }
99
100 WebCore::IDBDatabase* IDBTransaction::db()
101 {
102     return &m_database.get();
103 }
104
105 IDBConnectionToServer& IDBTransaction::serverConnection()
106 {
107     return m_database->serverConnection();
108 }
109
110 RefPtr<DOMError> IDBTransaction::error() const
111 {
112     ASSERT_NOT_REACHED();
113     return nullptr;
114 }
115
116 RefPtr<WebCore::IDBObjectStore> IDBTransaction::objectStore(const String& objectStoreName, ExceptionCode& ec)
117 {
118     LOG(IndexedDB, "IDBTransaction::objectStore");
119
120     if (objectStoreName.isEmpty()) {
121         ec = NOT_FOUND_ERR;
122         return nullptr;
123     }
124
125     if (isFinishedOrFinishing()) {
126         ec = INVALID_STATE_ERR;
127         return nullptr;
128     }
129
130     auto iterator = m_referencedObjectStores.find(objectStoreName);
131     if (iterator != m_referencedObjectStores.end())
132         return iterator->value;
133
134     bool found = false;
135     for (auto& objectStore : m_info.objectStores()) {
136         if (objectStore == objectStoreName) {
137             found = true;
138             break;
139         }
140     }
141
142     auto* info = m_database->info().infoForExistingObjectStore(objectStoreName);
143     if (!info) {
144         ec = NOT_FOUND_ERR;
145         return nullptr;
146     }
147
148     // Version change transactions are scoped to every object store in the database.
149     if (!found && !isVersionChange()) {
150         ec = NOT_FOUND_ERR;
151         return nullptr;
152     }
153
154     auto objectStore = IDBObjectStore::create(*info, *this);
155     m_referencedObjectStores.set(objectStoreName, &objectStore.get());
156
157     return adoptRef(&objectStore.leakRef());
158 }
159
160 void IDBTransaction::abort(ExceptionCode& ec)
161 {
162     LOG(IndexedDB, "IDBTransaction::abort");
163
164     if (isFinishedOrFinishing()) {
165         ec = INVALID_STATE_ERR;
166         return;
167     }
168
169     m_state = IndexedDB::TransactionState::Aborting;
170     m_database->willAbortTransaction(*this);
171
172     auto operation = createTransactionOperation(*this, nullptr, &IDBTransaction::abortOnServer);
173     scheduleOperation(WTF::move(operation));
174 }
175
176 void IDBTransaction::abortOnServer(TransactionOperation&)
177 {
178     LOG(IndexedDB, "IDBTransaction::abortOnServer");
179     serverConnection().abortTransaction(*this);
180 }
181
182 const char* IDBTransaction::activeDOMObjectName() const
183 {
184     return "IDBTransaction";
185 }
186
187 bool IDBTransaction::canSuspendForPageCache() const
188 {
189     return false;
190 }
191
192 bool IDBTransaction::hasPendingActivity() const
193 {
194     if (m_state == IndexedDB::TransactionState::Inactive)
195         return !m_transactionOperationQueue.isEmpty() || !m_transactionOperationMap.isEmpty();
196
197     return m_state != IndexedDB::TransactionState::Finished;
198 }
199
200 bool IDBTransaction::isActive() const
201 {
202     return m_state == IndexedDB::TransactionState::Active;
203 }
204
205 bool IDBTransaction::isFinishedOrFinishing() const
206 {
207     return m_state == IndexedDB::TransactionState::Committing
208         || m_state == IndexedDB::TransactionState::Aborting
209         || m_state == IndexedDB::TransactionState::Finished;
210 }
211
212 void IDBTransaction::addRequest(IDBRequest& request)
213 {
214     ASSERT(!m_openRequests.contains(&request));
215     m_openRequests.add(&request);
216 }
217
218 void IDBTransaction::removeRequest(IDBRequest& request)
219 {
220     ASSERT(m_openRequests.contains(&request));
221     m_openRequests.remove(&request);
222 }
223
224 void IDBTransaction::scheduleOperation(RefPtr<TransactionOperation>&& operation)
225 {
226     ASSERT(!m_transactionOperationMap.contains(operation->identifier()));
227
228     m_transactionOperationQueue.append(operation);
229     m_transactionOperationMap.set(operation->identifier(), WTF::move(operation));
230
231     scheduleOperationTimer();
232 }
233
234 void IDBTransaction::scheduleOperationTimer()
235 {
236     if (!m_operationTimer.isActive())
237         m_operationTimer.startOneShot(0);
238 }
239
240 void IDBTransaction::operationTimerFired()
241 {
242     LOG(IndexedDB, "IDBTransaction::operationTimerFired");
243
244     if (!m_startedOnServer)
245         return;
246
247     if (!m_transactionOperationQueue.isEmpty()) {
248         auto operation = m_transactionOperationQueue.takeFirst();
249         operation->perform();
250
251         return;
252     }
253
254     if (!m_transactionOperationMap.isEmpty() || !m_openRequests.isEmpty())
255         return;
256
257     if (!isFinishedOrFinishing())
258         commit();
259 }
260
261 void IDBTransaction::commit()
262 {
263     LOG(IndexedDB, "IDBTransaction::commit");
264
265     ASSERT(!isFinishedOrFinishing());
266
267     m_state = IndexedDB::TransactionState::Committing;
268     m_database->willCommitTransaction(*this);
269
270     auto operation = createTransactionOperation(*this, nullptr, &IDBTransaction::commitOnServer);
271     scheduleOperation(WTF::move(operation));
272 }
273
274 void IDBTransaction::commitOnServer(TransactionOperation&)
275 {
276     LOG(IndexedDB, "IDBTransaction::commitOnServer");
277     serverConnection().commitTransaction(*this);
278 }
279
280 void IDBTransaction::finishAbortOrCommit()
281 {
282     ASSERT(m_state != IndexedDB::TransactionState::Finished);
283     m_state = IndexedDB::TransactionState::Finished;
284
285     m_originalDatabaseInfo = nullptr;
286 }
287
288 void IDBTransaction::didStart(const IDBError& error)
289 {
290     LOG(IndexedDB, "IDBTransaction::didStart");
291
292     m_database->didStartTransaction(*this);
293
294     m_startedOnServer = true;
295
296     // It's possible the transaction failed to start on the server.
297     // That equates to an abort.
298     if (!error.isNull()) {
299         didAbort(error);
300         return;
301     }
302
303     scheduleOperationTimer();
304 }
305
306 void IDBTransaction::didAbort(const IDBError& error)
307 {
308     LOG(IndexedDB, "IDBTransaction::didAbort");
309
310     if (m_state == IndexedDB::TransactionState::Finished)
311         return;
312
313     m_database->didAbortTransaction(*this);
314
315     m_idbError = error;
316     fireOnAbort();
317
318     finishAbortOrCommit();
319 }
320
321 void IDBTransaction::didCommit(const IDBError& error)
322 {
323     LOG(IndexedDB, "IDBTransaction::didCommit");
324
325     ASSERT(m_state == IndexedDB::TransactionState::Committing);
326
327     if (error.isNull()) {
328         m_database->didCommitTransaction(*this);
329         fireOnComplete();
330     } else {
331         m_database->didAbortTransaction(*this);
332         m_idbError = error;
333         fireOnAbort();
334     }
335
336     finishAbortOrCommit();
337 }
338
339 void IDBTransaction::fireOnComplete()
340 {
341     LOG(IndexedDB, "IDBTransaction::fireOnComplete");
342     enqueueEvent(Event::create(eventNames().completeEvent, false, false));
343 }
344
345 void IDBTransaction::fireOnAbort()
346 {
347     LOG(IndexedDB, "IDBTransaction::fireOnAbort");
348     enqueueEvent(Event::create(eventNames().abortEvent, true, false));
349 }
350
351 void IDBTransaction::enqueueEvent(Ref<Event>&& event)
352 {
353     ASSERT(m_state != IndexedDB::TransactionState::Finished);
354
355     if (!scriptExecutionContext())
356         return;
357
358     event->setTarget(this);
359     scriptExecutionContext()->eventQueue().enqueueEvent(WTF::move(event));
360 }
361
362 bool IDBTransaction::dispatchEvent(Event& event)
363 {
364     LOG(IndexedDB, "IDBTransaction::dispatchEvent");
365
366     ASSERT(scriptExecutionContext());
367     ASSERT(event.target() == this);
368     ASSERT(event.type() == eventNames().completeEvent || event.type() == eventNames().abortEvent);
369
370     Vector<RefPtr<EventTarget>> targets;
371     targets.append(this);
372     targets.append(db());
373
374     return IDBEventDispatcher::dispatch(event, targets);
375 }
376
377 Ref<IDBObjectStore> IDBTransaction::createObjectStore(const IDBObjectStoreInfo& info)
378 {
379     LOG(IndexedDB, "IDBTransaction::createObjectStore");
380     ASSERT(isVersionChange());
381
382     Ref<IDBObjectStore> objectStore = IDBObjectStore::create(info, *this);
383     m_referencedObjectStores.set(info.name(), &objectStore.get());
384
385     auto operation = createTransactionOperation(*this, &IDBTransaction::didCreateObjectStoreOnServer, &IDBTransaction::createObjectStoreOnServer, info);
386     scheduleOperation(WTF::move(operation));
387
388     return WTF::move(objectStore);
389 }
390
391 void IDBTransaction::createObjectStoreOnServer(TransactionOperation& operation, const IDBObjectStoreInfo& info)
392 {
393     LOG(IndexedDB, "IDBTransaction::createObjectStoreOnServer");
394
395     ASSERT(isVersionChange());
396
397     m_database->serverConnection().createObjectStore(operation, info);
398 }
399
400 void IDBTransaction::didCreateObjectStoreOnServer(const IDBResultData& resultData)
401 {
402     LOG(IndexedDB, "IDBTransaction::didCreateObjectStoreOnServer");
403
404     ASSERT_UNUSED(resultData, resultData.type() == IDBResultType::CreateObjectStoreSuccess);
405 }
406
407 Ref<IDBIndex> IDBTransaction::createIndex(IDBObjectStore& objectStore, const IDBIndexInfo& info)
408 {
409     LOG(IndexedDB, "IDBTransaction::createIndex");
410     ASSERT(isVersionChange());
411
412     Ref<IDBIndex> index = IDBIndex::create(info, objectStore);
413
414     auto operation = createTransactionOperation(*this, &IDBTransaction::didCreateIndexOnServer, &IDBTransaction::createIndexOnServer, info);
415     scheduleOperation(WTF::move(operation));
416
417     return WTF::move(index);
418 }
419
420 void IDBTransaction::createIndexOnServer(TransactionOperation& operation, const IDBIndexInfo& info)
421 {
422     LOG(IndexedDB, "IDBTransaction::createIndexOnServer");
423
424     ASSERT(isVersionChange());
425
426     m_database->serverConnection().createIndex(operation, info);
427 }
428
429 void IDBTransaction::didCreateIndexOnServer(const IDBResultData& resultData)
430 {
431     LOG(IndexedDB, "IDBTransaction::didCreateIndexOnServer");
432
433     ASSERT_UNUSED(resultData, resultData.type() == IDBResultType::CreateIndexSuccess);
434 }
435
436 Ref<IDBRequest> IDBTransaction::requestOpenCursor(ScriptExecutionContext& context, IDBObjectStore& objectStore, const IDBCursorInfo& info)
437 {
438     LOG(IndexedDB, "IDBTransaction::requestOpenCursor");
439
440     return doRequestOpenCursor(context, IDBCursorWithValue::create(*this, objectStore, info));
441 }
442
443 Ref<IDBRequest> IDBTransaction::requestOpenCursor(ScriptExecutionContext& context, IDBIndex& index, const IDBCursorInfo& info)
444 {
445     LOG(IndexedDB, "IDBTransaction::requestOpenCursor");
446
447     if (info.cursorType() == IndexedDB::CursorType::KeyOnly)
448         return doRequestOpenCursor(context, IDBCursor::create(*this, index, info));
449
450     return doRequestOpenCursor(context, IDBCursorWithValue::create(*this, index, info));
451 }
452
453 Ref<IDBRequest> IDBTransaction::doRequestOpenCursor(ScriptExecutionContext& context, Ref<IDBCursor>&& cursor)
454 {
455     ASSERT(isActive());
456
457     Ref<IDBRequest> request = IDBRequest::create(context, cursor.get(), *this);
458     addRequest(request.get());
459
460     auto operation = createTransactionOperation(*this, request.get(), &IDBTransaction::didOpenCursorOnServer, &IDBTransaction::openCursorOnServer, cursor->info());
461     scheduleOperation(WTF::move(operation));
462
463     return WTF::move(request);
464 }
465
466 void IDBTransaction::openCursorOnServer(TransactionOperation& operation, const IDBCursorInfo& info)
467 {
468     LOG(IndexedDB, "IDBTransaction::openCursorOnServer");
469
470     m_database->serverConnection().openCursor(operation, info);
471 }
472
473 void IDBTransaction::didOpenCursorOnServer(IDBRequest& request, const IDBResultData& resultData)
474 {
475     LOG(IndexedDB, "IDBTransaction::didOpenCursorOnServer");
476
477     request.didOpenOrIterateCursor(resultData);
478 }
479
480 void IDBTransaction::iterateCursor(IDBCursor& cursor, const IDBKeyData& key, unsigned long count)
481 {
482     LOG(IndexedDB, "IDBTransaction::iterateCursor");
483     ASSERT(isActive());
484     ASSERT(cursor.request());
485
486     addRequest(*cursor.request());
487
488     auto operation = createTransactionOperation(*this, *cursor.request(), &IDBTransaction::didIterateCursorOnServer, &IDBTransaction::iterateCursorOnServer, key, count);
489     scheduleOperation(WTF::move(operation));
490 }
491
492 void IDBTransaction::iterateCursorOnServer(TransactionOperation& operation, const IDBKeyData& key, const unsigned long& count)
493 {
494     LOG(IndexedDB, "IDBTransaction::iterateCursorOnServer");
495
496     serverConnection().iterateCursor(operation, key, count);
497 }
498
499 void IDBTransaction::didIterateCursorOnServer(IDBRequest& request, const IDBResultData& resultData)
500 {
501     LOG(IndexedDB, "IDBTransaction::didIterateCursorOnServer");
502
503     request.didOpenOrIterateCursor(resultData);
504 }
505
506 Ref<IDBRequest> IDBTransaction::requestGetRecord(ScriptExecutionContext& context, IDBObjectStore& objectStore, const IDBKeyRangeData& keyRangeData)
507 {
508     LOG(IndexedDB, "IDBTransaction::requestGetRecord");
509     ASSERT(isActive());
510     ASSERT(!keyRangeData.isNull);
511
512     Ref<IDBRequest> request = IDBRequest::create(context, objectStore, *this);
513     addRequest(request.get());
514
515     auto operation = createTransactionOperation(*this, request.get(), &IDBTransaction::didGetRecordOnServer, &IDBTransaction::getRecordOnServer, keyRangeData);
516     scheduleOperation(WTF::move(operation));
517
518     return WTF::move(request);
519 }
520
521 Ref<IDBRequest> IDBTransaction::requestGetValue(ScriptExecutionContext& context, IDBIndex& index, const IDBKeyRangeData& range)
522 {
523     LOG(IndexedDB, "IDBTransaction::requestGetValue");
524     return requestIndexRecord(context, index, IndexedDB::IndexRecordType::Value, range);
525 }
526
527 Ref<IDBRequest> IDBTransaction::requestGetKey(ScriptExecutionContext& context, IDBIndex& index, const IDBKeyRangeData& range)
528 {
529     LOG(IndexedDB, "IDBTransaction::requestGetValue");
530     return requestIndexRecord(context, index, IndexedDB::IndexRecordType::Key, range);
531 }
532
533 Ref<IDBRequest> IDBTransaction::requestIndexRecord(ScriptExecutionContext& context, IDBIndex& index, IndexedDB::IndexRecordType type, const IDBKeyRangeData&range)
534 {
535     LOG(IndexedDB, "IDBTransaction::requestGetValue");
536     ASSERT(isActive());
537     ASSERT(!range.isNull);
538
539     Ref<IDBRequest> request = IDBRequest::createGet(context, index, type, *this);
540     addRequest(request.get());
541
542     auto operation = createTransactionOperation(*this, request.get(), &IDBTransaction::didGetRecordOnServer, &IDBTransaction::getRecordOnServer, range);
543     scheduleOperation(WTF::move(operation));
544
545     return WTF::move(request);
546 }
547
548 void IDBTransaction::getRecordOnServer(TransactionOperation& operation, const IDBKeyRangeData& keyRange)
549 {
550     LOG(IndexedDB, "IDBTransaction::getRecordOnServer");
551
552     serverConnection().getRecord(operation, keyRange);
553 }
554
555 void IDBTransaction::didGetRecordOnServer(IDBRequest& request, const IDBResultData& resultData)
556 {
557     LOG(IndexedDB, "IDBTransaction::didGetRecordOnServer");
558
559     const IDBGetResult& result = resultData.getResult();
560
561     if (request.sourceIndexIdentifier() && request.requestedIndexRecordType() == IndexedDB::IndexRecordType::Key) {
562         if (!result.keyData.isNull())
563             request.setResult(&result.keyData);
564         else
565             request.setResultToUndefined();
566     } else {
567         if (resultData.getResult().valueBuffer.data())
568             request.setResultToStructuredClone(resultData.getResult().valueBuffer);
569         else
570             request.setResultToUndefined();
571     }
572
573     request.requestCompleted(resultData);
574 }
575
576 Ref<IDBRequest> IDBTransaction::requestCount(ScriptExecutionContext& context, IDBObjectStore& objectStore, const IDBKeyRangeData& range)
577 {
578     LOG(IndexedDB, "IDBTransaction::requestCount (IDBObjectStore)");
579     ASSERT(isActive());
580     ASSERT(!range.isNull);
581
582     Ref<IDBRequest> request = IDBRequest::create(context, objectStore, *this);
583     addRequest(request.get());
584
585     scheduleOperation(createTransactionOperation(*this, request.get(), &IDBTransaction::didGetCountOnServer, &IDBTransaction::getCountOnServer, range));
586
587     return request;
588 }
589
590 Ref<IDBRequest> IDBTransaction::requestCount(ScriptExecutionContext& context, IDBIndex& index, const IDBKeyRangeData& range)
591 {
592     LOG(IndexedDB, "IDBTransaction::requestCount (IDBIndex)");
593     ASSERT(isActive());
594     ASSERT(!range.isNull);
595
596     Ref<IDBRequest> request = IDBRequest::createCount(context, index, *this);
597     addRequest(request.get());
598
599     scheduleOperation(createTransactionOperation(*this, request.get(), &IDBTransaction::didGetCountOnServer, &IDBTransaction::getCountOnServer, range));
600
601     return request;
602 }
603
604 void IDBTransaction::getCountOnServer(TransactionOperation& operation, const IDBKeyRangeData& keyRange)
605 {
606     LOG(IndexedDB, "IDBTransaction::getCountOnServer");
607
608     serverConnection().getCount(operation, keyRange);
609 }
610
611 void IDBTransaction::didGetCountOnServer(IDBRequest& request, const IDBResultData& resultData)
612 {
613     LOG(IndexedDB, "IDBTransaction::didGetCountOnServer");
614
615     request.setResult(resultData.resultInteger());
616     request.requestCompleted(resultData);
617 }
618
619 Ref<IDBRequest> IDBTransaction::requestDeleteRecord(ScriptExecutionContext& context, IDBObjectStore& objectStore, const IDBKeyRangeData& range)
620 {
621     LOG(IndexedDB, "IDBTransaction::requestDeleteRecord");
622     ASSERT(isActive());
623     ASSERT(!range.isNull);
624
625     Ref<IDBRequest> request = IDBRequest::create(context, objectStore, *this);
626     addRequest(request.get());
627
628     scheduleOperation(createTransactionOperation(*this, request.get(), &IDBTransaction::didDeleteRecordOnServer, &IDBTransaction::deleteRecordOnServer, range));
629     return request;
630 }
631
632 void IDBTransaction::deleteRecordOnServer(TransactionOperation& operation, const IDBKeyRangeData& keyRange)
633 {
634     LOG(IndexedDB, "IDBTransaction::deleteRecordOnServer");
635
636     serverConnection().deleteRecord(operation, keyRange);
637 }
638
639 void IDBTransaction::didDeleteRecordOnServer(IDBRequest& request, const IDBResultData& resultData)
640 {
641     LOG(IndexedDB, "IDBTransaction::didDeleteRecordOnServer");
642
643     request.setResultToUndefined();
644     request.requestCompleted(resultData);
645 }
646
647 Ref<IDBRequest> IDBTransaction::requestClearObjectStore(ScriptExecutionContext& context, IDBObjectStore& objectStore)
648 {
649     LOG(IndexedDB, "IDBTransaction::requestClearObjectStore");
650     ASSERT(isActive());
651
652     Ref<IDBRequest> request = IDBRequest::create(context, objectStore, *this);
653     addRequest(request.get());
654
655     uint64_t objectStoreIdentifier = objectStore.info().identifier();
656     auto operation = createTransactionOperation(*this, request.get(), &IDBTransaction::didClearObjectStoreOnServer, &IDBTransaction::clearObjectStoreOnServer, objectStoreIdentifier);
657     scheduleOperation(WTF::move(operation));
658
659     return WTF::move(request);
660 }
661
662 void IDBTransaction::clearObjectStoreOnServer(TransactionOperation& operation, const uint64_t& objectStoreIdentifier)
663 {
664     LOG(IndexedDB, "IDBTransaction::clearObjectStoreOnServer");
665
666     serverConnection().clearObjectStore(operation, objectStoreIdentifier);
667 }
668
669 void IDBTransaction::didClearObjectStoreOnServer(IDBRequest& request, const IDBResultData& resultData)
670 {
671     LOG(IndexedDB, "IDBTransaction::didClearObjectStoreOnServer");
672
673     request.setResultToUndefined();
674     request.requestCompleted(resultData);
675 }
676
677 Ref<IDBRequest> IDBTransaction::requestPutOrAdd(ScriptExecutionContext& context, IDBObjectStore& objectStore, IDBKey* key, SerializedScriptValue& value, IndexedDB::ObjectStoreOverwriteMode overwriteMode)
678 {
679     LOG(IndexedDB, "IDBTransaction::requestPutOrAdd");
680     ASSERT(isActive());
681     ASSERT(!isReadOnly());
682     ASSERT(objectStore.info().autoIncrement() || key);
683
684     Ref<IDBRequest> request = IDBRequest::create(context, objectStore, *this);
685     addRequest(request.get());
686
687     auto operation = createTransactionOperation(*this, request.get(), &IDBTransaction::didPutOrAddOnServer, &IDBTransaction::putOrAddOnServer, key, &value, overwriteMode);
688     scheduleOperation(WTF::move(operation));
689
690     return WTF::move(request);
691 }
692
693 void IDBTransaction::putOrAddOnServer(TransactionOperation& operation, RefPtr<IDBKey> key, RefPtr<SerializedScriptValue> value, const IndexedDB::ObjectStoreOverwriteMode& overwriteMode)
694 {
695     LOG(IndexedDB, "IDBTransaction::putOrAddOnServer");
696
697     ASSERT(!isReadOnly());
698
699     serverConnection().putOrAdd(operation, key, value, overwriteMode);
700 }
701
702 void IDBTransaction::didPutOrAddOnServer(IDBRequest& request, const IDBResultData& resultData)
703 {
704     LOG(IndexedDB, "IDBTransaction::didPutOrAddOnServer");
705
706     request.setResult(resultData.resultKey());
707     request.requestCompleted(resultData);
708 }
709
710 void IDBTransaction::deleteObjectStore(const String& objectStoreName)
711 {
712     LOG(IndexedDB, "IDBTransaction::deleteObjectStore");
713
714     ASSERT(isVersionChange());
715
716     if (auto objectStore = m_referencedObjectStores.take(objectStoreName))
717         objectStore->markAsDeleted();
718
719     auto operation = createTransactionOperation(*this, &IDBTransaction::didDeleteObjectStoreOnServer, &IDBTransaction::deleteObjectStoreOnServer, objectStoreName);
720     scheduleOperation(WTF::move(operation));
721 }
722
723 void IDBTransaction::deleteObjectStoreOnServer(TransactionOperation& operation, const String& objectStoreName)
724 {
725     LOG(IndexedDB, "IDBTransaction::deleteObjectStoreOnServer");
726     ASSERT(isVersionChange());
727
728     serverConnection().deleteObjectStore(operation, objectStoreName);
729 }
730
731 void IDBTransaction::didDeleteObjectStoreOnServer(const IDBResultData& resultData)
732 {
733     LOG(IndexedDB, "IDBTransaction::didDeleteObjectStoreOnServer");
734     ASSERT_UNUSED(resultData, resultData.type() == IDBResultType::DeleteObjectStoreSuccess);
735 }
736
737 void IDBTransaction::operationDidComplete(TransactionOperation& operation)
738 {
739     ASSERT(m_transactionOperationMap.get(operation.identifier()) == &operation);
740     m_transactionOperationMap.remove(operation.identifier());
741
742     scheduleOperationTimer();
743 }
744
745 void IDBTransaction::establishOnServer()
746 {
747     LOG(IndexedDB, "IDBTransaction::establishOnServer");
748
749     serverConnection().establishTransaction(*this);
750 }
751
752 void IDBTransaction::activate()
753 {
754     if (isFinishedOrFinishing())
755         return;
756
757     m_state = IndexedDB::TransactionState::Active;
758 }
759
760 void IDBTransaction::deactivate()
761 {
762     if (m_state == IndexedDB::TransactionState::Active)
763         m_state = IndexedDB::TransactionState::Inactive;
764
765     scheduleOperationTimer();
766 }
767
768 } // namespace IDBClient
769 } // namespace WebCore
770
771 #endif // ENABLE(INDEXED_DATABASE)