Modern IDB: LayoutTest imported/w3c/indexeddb/keyorder-private.html is flaky.
[WebKit-https.git] / Source / WebCore / Modules / indexeddb / IDBKeyData.cpp
1 /*
2  * Copyright (C) 2014 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 "IDBKeyData.h"
28
29 #if ENABLE(INDEXED_DATABASE)
30
31 #include "KeyedCoding.h"
32 #include <wtf/text/StringBuilder.h>
33
34 namespace WebCore {
35
36 IDBKeyData::IDBKeyData(const IDBKey* key)
37     : m_type(KeyType::Invalid)
38 {
39     if (!key) {
40         m_isNull = true;
41         return;
42     }
43
44     m_type = key->type();
45
46     switch (m_type) {
47     case KeyType::Invalid:
48         break;
49     case KeyType::Array:
50         for (auto& key2 : key->array())
51             m_arrayValue.append(IDBKeyData(key2.get()));
52         break;
53     case KeyType::String:
54         m_stringValue = key->string();
55         break;
56     case KeyType::Date:
57         m_numberValue = key->date();
58         break;
59     case KeyType::Number:
60         m_numberValue = key->number();
61         break;
62     case KeyType::Max:
63     case KeyType::Min:
64         break;
65     }
66 }
67
68 PassRefPtr<IDBKey> IDBKeyData::maybeCreateIDBKey() const
69 {
70     if (m_isNull)
71         return nullptr;
72
73     switch (m_type) {
74     case KeyType::Invalid:
75         return IDBKey::createInvalid();
76     case KeyType::Array:
77         {
78             Vector<RefPtr<IDBKey>> array;
79             for (auto& keyData : m_arrayValue) {
80                 array.append(keyData.maybeCreateIDBKey());
81                 ASSERT(array.last());
82             }
83             return IDBKey::createArray(array);
84         }
85     case KeyType::String:
86         return IDBKey::createString(m_stringValue);
87     case KeyType::Date:
88         return IDBKey::createDate(m_numberValue);
89     case KeyType::Number:
90         return IDBKey::createNumber(m_numberValue);
91     case KeyType::Max:
92     case KeyType::Min:
93         ASSERT_NOT_REACHED();
94         return nullptr;
95     }
96
97     ASSERT_NOT_REACHED();
98     return nullptr;
99 }
100
101 IDBKeyData IDBKeyData::isolatedCopy() const
102 {
103     IDBKeyData result;
104     result.m_type = m_type;
105     result.m_isNull = m_isNull;
106
107     switch (m_type) {
108     case KeyType::Invalid:
109         return result;
110     case KeyType::Array:
111         for (auto& key : m_arrayValue)
112             result.m_arrayValue.append(key.isolatedCopy());
113         return result;
114     case KeyType::String:
115         result.m_stringValue = m_stringValue.isolatedCopy();
116         return result;
117     case KeyType::Date:
118     case KeyType::Number:
119         result.m_numberValue = m_numberValue;
120         return result;
121     case KeyType::Max:
122     case KeyType::Min:
123         return result;
124     }
125
126     ASSERT_NOT_REACHED();
127     return result;
128 }
129
130 void IDBKeyData::encode(KeyedEncoder& encoder) const
131 {
132     encoder.encodeBool("null", m_isNull);
133     if (m_isNull)
134         return;
135
136     encoder.encodeEnum("m_type", m_type);
137
138     switch (m_type) {
139     case KeyType::Invalid:
140         return;
141     case KeyType::Array:
142         encoder.encodeObjects("array", m_arrayValue.begin(), m_arrayValue.end(), [](KeyedEncoder& encoder, const IDBKeyData& key) {
143             key.encode(encoder);
144         });
145         return;
146     case KeyType::String:
147         encoder.encodeString("string", m_stringValue);
148         return;
149     case KeyType::Date:
150     case KeyType::Number:
151         encoder.encodeDouble("number", m_numberValue);
152         return;
153     case KeyType::Max:
154     case KeyType::Min:
155         return;
156     }
157
158     ASSERT_NOT_REACHED();
159 }
160
161 bool IDBKeyData::decode(KeyedDecoder& decoder, IDBKeyData& result)
162 {
163     if (!decoder.decodeBool("null", result.m_isNull))
164         return false;
165
166     if (result.m_isNull)
167         return true;
168
169     auto enumFunction = [](int64_t value) {
170         return value == KeyType::Max
171             || value == KeyType::Invalid
172             || value == KeyType::Array
173             || value == KeyType::String
174             || value == KeyType::Date
175             || value == KeyType::Number
176             || value == KeyType::Min;
177     };
178     if (!decoder.decodeEnum("m_type", result.m_type, enumFunction))
179         return false;
180
181     if (result.m_type == KeyType::Invalid)
182         return true;
183
184     if (result.m_type == KeyType::Max)
185         return true;
186
187     if (result.m_type == KeyType::Min)
188         return true;
189
190     if (result.m_type == KeyType::String)
191         return decoder.decodeString("string", result.m_stringValue);
192
193     if (result.m_type == KeyType::Number || result.m_type == KeyType::Date)
194         return decoder.decodeDouble("number", result.m_numberValue);
195
196     ASSERT(result.m_type == KeyType::Array);
197
198     auto arrayFunction = [](KeyedDecoder& decoder, IDBKeyData& result) {
199         return decode(decoder, result);
200     };
201     
202     result.m_arrayValue.clear();
203     return decoder.decodeObjects("array", result.m_arrayValue, arrayFunction);
204 }
205
206 int IDBKeyData::compare(const IDBKeyData& other) const
207 {
208     if (m_type == KeyType::Invalid) {
209         if (other.m_type != KeyType::Invalid)
210             return -1;
211         if (other.m_type == KeyType::Invalid)
212             return 0;
213     } else if (other.m_type == KeyType::Invalid)
214         return 1;
215
216     // The IDBKey::m_type enum is in reverse sort order.
217     if (m_type != other.m_type)
218         return m_type < other.m_type ? 1 : -1;
219
220     // The types are the same, so handle actual value comparison.
221     switch (m_type) {
222     case KeyType::Invalid:
223         // Invalid type should have been fully handled above
224         ASSERT_NOT_REACHED();
225         return 0;
226     case KeyType::Array:
227         for (size_t i = 0; i < m_arrayValue.size() && i < other.m_arrayValue.size(); ++i) {
228             if (int result = m_arrayValue[i].compare(other.m_arrayValue[i]))
229                 return result;
230         }
231         if (m_arrayValue.size() < other.m_arrayValue.size())
232             return -1;
233         if (m_arrayValue.size() > other.m_arrayValue.size())
234             return 1;
235         return 0;
236     case KeyType::String:
237         return codePointCompare(m_stringValue, other.m_stringValue);
238     case KeyType::Date:
239     case KeyType::Number:
240         if (m_numberValue == other.m_numberValue)
241             return 0;
242         return m_numberValue > other.m_numberValue ? 1 : -1;
243     case KeyType::Max:
244     case KeyType::Min:
245         return 0;
246     }
247
248     ASSERT_NOT_REACHED();
249     return 0;
250 }
251
252 #ifndef NDEBUG
253 String IDBKeyData::loggingString() const
254 {
255     if (m_isNull)
256         return "<null>";
257
258     String result;
259
260     switch (m_type) {
261     case KeyType::Invalid:
262         return "<invalid>";
263     case KeyType::Array: {
264         StringBuilder builder;
265         builder.appendLiteral("<array> - { ");
266         for (size_t i = 0; i < m_arrayValue.size(); ++i) {
267             builder.append(m_arrayValue[i].loggingString());
268             if (i < m_arrayValue.size() - 1)
269                 builder.appendLiteral(", ");
270         }
271         builder.appendLiteral(" }");
272         result = builder.toString();
273         break;
274     }
275     case KeyType::String:
276         result = "<string> - " + m_stringValue;
277         break;
278     case KeyType::Date:
279         return String::format("<date> - %f", m_numberValue);
280     case KeyType::Number:
281         return String::format("<number> - %f", m_numberValue);
282     case KeyType::Max:
283         return "<maximum>";
284     case KeyType::Min:
285         return "<minimum>";
286     default:
287         return String();
288     }
289
290     if (result.length() > 150) {
291         result.truncate(147);
292         result.append(WTF::ASCIILiteral("..."));
293     }
294
295     return result;
296 }
297 #endif
298
299 void IDBKeyData::setArrayValue(const Vector<IDBKeyData>& value)
300 {
301     *this = IDBKeyData();
302     m_arrayValue = value;
303     m_type = KeyType::Array;
304     m_isNull = false;
305 }
306
307 void IDBKeyData::setStringValue(const String& value)
308 {
309     *this = IDBKeyData();
310     m_stringValue = value;
311     m_type = KeyType::String;
312     m_isNull = false;
313 }
314
315 void IDBKeyData::setDateValue(double value)
316 {
317     *this = IDBKeyData();
318     m_numberValue = value;
319     m_type = KeyType::Date;
320     m_isNull = false;
321 }
322
323 void IDBKeyData::setNumberValue(double value)
324 {
325     *this = IDBKeyData();
326     m_numberValue = value;
327     m_type = KeyType::Number;
328     m_isNull = false;
329 }
330
331 IDBKeyData IDBKeyData::deletedValue()
332 {
333     IDBKeyData result;
334     result.m_isNull = false;
335     result.m_isDeletedValue = true;
336     return result;
337 }
338
339 bool IDBKeyData::operator<(const IDBKeyData& rhs) const
340 {
341     return compare(rhs) < 0;
342 }
343
344 bool IDBKeyData::operator==(const IDBKeyData& other) const
345 {
346     if (m_type != other.m_type || m_isNull != other.m_isNull || m_isDeletedValue != other.m_isDeletedValue)
347         return false;
348     switch (m_type) {
349     case KeyType::Invalid:
350     case KeyType::Max:
351     case KeyType::Min:
352         return true;
353     case KeyType::Number:
354     case KeyType::Date:
355         return m_numberValue == other.m_numberValue;
356     case KeyType::String:
357         return m_stringValue == other.m_stringValue;
358     case KeyType::Array:
359         return m_arrayValue == other.m_arrayValue;
360     }
361     RELEASE_ASSERT_NOT_REACHED();
362 }
363
364 } // namespace WebCore
365
366 #endif // ENABLE(INDEXED_DATABASE)