Modern IDB: Class-ify IDBGetResult making it impossible to get the data members wrong.
[WebKit-https.git] / Source / WebCore / Modules / indexeddb / server / MemoryIndexCursor.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. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "MemoryIndexCursor.h"
28
29 #if ENABLE(INDEXED_DATABASE)
30
31 #include "IDBCursorInfo.h"
32 #include "IndexValueStore.h"
33 #include "Logging.h"
34 #include "MemoryCursor.h"
35 #include "MemoryIndex.h"
36 #include "MemoryObjectStore.h"
37
38 namespace WebCore {
39 namespace IDBServer {
40
41 MemoryIndexCursor::MemoryIndexCursor(MemoryIndex& index, const IDBCursorInfo& info)
42     : MemoryCursor(info)
43     , m_index(index)
44 {
45     auto* valueStore = m_index.valueStore();
46     if (!valueStore)
47         return;
48
49     IndexValueStore::Iterator iterator;
50     if (m_info.isDirectionForward())
51         iterator = valueStore->find(m_info.range().lowerKey, m_info.range().lowerOpen);
52     else
53         iterator = valueStore->reverseFind(m_info.range().upperKey, m_info.range().upperOpen);
54
55     if (iterator.isValid()) {
56         m_currentKey = iterator.key();
57         m_currentPrimaryKey = iterator.primaryKey();
58         m_index.cursorDidBecomeClean(*this);
59     }
60 }
61
62 MemoryIndexCursor::~MemoryIndexCursor()
63 {
64 }
65
66 void MemoryIndexCursor::currentData(IDBGetResult& getResult)
67 {
68     if (m_info.cursorType() == IndexedDB::CursorType::KeyOnly)
69         getResult = { m_currentKey, m_currentPrimaryKey };
70     else
71         getResult = { m_currentKey, m_currentPrimaryKey, m_index.objectStore().valueForKey(m_currentPrimaryKey) };
72 }
73
74 void MemoryIndexCursor::iterate(const IDBKeyData& key, uint32_t count, IDBGetResult& getResult)
75 {
76     LOG(IndexedDB, "MemoryIndexCursor::iterate to key %s, %u count", key.loggingString().utf8().data(), count);
77
78     if (key.isValid()) {
79         // Cannot iterator by both a count and to a key
80         ASSERT(!count);
81
82         auto* valueStore = m_index.valueStore();
83         if (!valueStore) {
84             m_currentKey = { };
85             m_currentPrimaryKey = { };
86             getResult = { };
87             return;
88         }
89
90         if (m_info.isDirectionForward())
91             m_currentIterator = valueStore->find(m_currentKey);
92         else
93             m_currentIterator = valueStore->reverseFind(m_currentKey);
94
95         if (!m_currentIterator.isValid()) {
96             m_currentKey = { };
97             m_currentPrimaryKey = { };
98             getResult = { };
99             return;
100         }
101
102         m_index.cursorDidBecomeClean(*this);
103
104         m_currentKey = m_currentIterator.key();
105         m_currentPrimaryKey = m_currentIterator.primaryKey();
106         currentData(getResult);
107
108         return;
109     }
110
111     // If there was not a valid key argument and no positive count argument
112     // that means the default iteration count of "1"
113     if (!count)
114         count = 1;
115
116     if (!m_currentIterator.isValid()) {
117         auto* valueStore = m_index.valueStore();
118         if (!valueStore) {
119             m_currentKey = { };
120             m_currentPrimaryKey = { };
121             getResult = { };
122             return;
123         }
124
125         switch (m_info.cursorDirection()) {
126         case IndexedDB::CursorDirection::Next:
127             m_currentIterator = valueStore->find(m_currentKey, m_currentPrimaryKey);
128             break;
129         case IndexedDB::CursorDirection::NextNoDuplicate:
130             m_currentIterator = valueStore->find(m_currentKey, true);
131             break;
132         case IndexedDB::CursorDirection::Prev:
133             m_currentIterator = valueStore->reverseFind(m_currentKey, m_currentPrimaryKey);
134             break;
135         case IndexedDB::CursorDirection::PrevNoDuplicate:
136             m_currentIterator = valueStore->reverseFind(m_currentKey, true);
137             break;
138         }
139
140         if (!m_currentIterator.isValid()) {
141             m_currentKey = { };
142             m_currentPrimaryKey = { };
143             getResult = { };
144             return;
145         }
146
147         m_index.cursorDidBecomeClean(*this);
148
149         // If we restored the current iterator and it does *not* match the current key/primaryKey,
150         // then it is the next record in line and we should consider that an iteration.
151         if (m_currentKey != m_currentIterator.key() || m_currentPrimaryKey != m_currentIterator.primaryKey())
152             --count;
153     }
154
155     ASSERT(m_currentIterator.isValid());
156
157     while (count) {
158         if (m_info.isDirectionNoDuplicate())
159             m_currentIterator.nextIndexEntry();
160         else
161             ++m_currentIterator;
162
163         if (!m_currentIterator.isValid())
164             break;
165
166         --count;
167     }
168
169     if (m_currentIterator.isValid() && !m_info.range().containsKey(m_currentIterator.key()))
170         m_currentIterator.invalidate();
171
172     // Not having a valid iterator after finishing any iteration means we've reached the end of the cursor.
173     if (!m_currentIterator.isValid()) {
174         m_currentKey = { };
175         m_currentPrimaryKey = { };
176         getResult = { };
177         return;
178     }
179
180     m_currentKey = m_currentIterator.key();
181     m_currentPrimaryKey = m_currentIterator.primaryKey();
182     currentData(getResult);
183 }
184
185 void MemoryIndexCursor::indexRecordsAllChanged()
186 {
187     m_currentIterator.invalidate();
188     m_index.cursorDidBecomeDirty(*this);
189 }
190
191 void MemoryIndexCursor::indexValueChanged(const IDBKeyData& key, const IDBKeyData& primaryKey)
192 {
193     if (m_currentKey != key || m_currentPrimaryKey != primaryKey)
194         return;
195
196     m_currentIterator.invalidate();
197     m_index.cursorDidBecomeDirty(*this);
198 }
199
200 } // namespace IDBServer
201 } // namespace WebCore
202
203 #endif // ENABLE(INDEXED_DATABASE)