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