Make IDBKeyData from a struct to a class.
[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     switch (m_type) {
259     case KeyType::Invalid:
260         return "<invalid>";
261     case KeyType::Array:
262         {
263             StringBuilder result;
264             result.appendLiteral("<array> - { ");
265             for (size_t i = 0; i < m_arrayValue.size(); ++i) {
266                 result.append(m_arrayValue[i].loggingString());
267                 if (i < m_arrayValue.size() - 1)
268                     result.appendLiteral(", ");
269             }
270             result.appendLiteral(" }");
271             return result.toString();
272         }
273     case KeyType::String:
274         return "<string> - " + m_stringValue;
275     case KeyType::Date:
276         return String::format("Date m_type - %f", m_numberValue);
277     case KeyType::Number:
278         return String::format("<number> - %f", m_numberValue);
279     case KeyType::Max:
280         return "<maximum>";
281     case KeyType::Min:
282         return "<minimum>";
283     default:
284         return String();
285     }
286     ASSERT_NOT_REACHED();
287 }
288 #endif
289
290 void IDBKeyData::setArrayValue(const Vector<IDBKeyData>& value)
291 {
292     *this = IDBKeyData();
293     m_arrayValue = value;
294     m_type = KeyType::Array;
295     m_isNull = false;
296 }
297
298 void IDBKeyData::setStringValue(const String& value)
299 {
300     *this = IDBKeyData();
301     m_stringValue = value;
302     m_type = KeyType::String;
303     m_isNull = false;
304 }
305
306 void IDBKeyData::setDateValue(double value)
307 {
308     *this = IDBKeyData();
309     m_numberValue = value;
310     m_type = KeyType::Date;
311     m_isNull = false;
312 }
313
314 void IDBKeyData::setNumberValue(double value)
315 {
316     *this = IDBKeyData();
317     m_numberValue = value;
318     m_type = KeyType::Number;
319     m_isNull = false;
320 }
321
322 }
323
324 #endif // ENABLE(INDEXED_DATABASE)