#include "config.h"
#include "IDBKeyData.h"
#if ENABLE(INDEXED_DATABASE)
#include "KeyedCoding.h"
#include <wtf/text/StringBuilder.h>
namespace WebCore {
IDBKeyData::IDBKeyData(const IDBKey* key)
: type(IDBKey::InvalidType)
, numberValue(0)
, isNull(false)
{
if (!key) {
isNull = true;
return;
}
type = key->type();
numberValue = 0;
switch (type) {
case IDBKey::InvalidType:
break;
case IDBKey::ArrayType:
for (auto& key2 : key->array())
arrayValue.append(IDBKeyData(key2.get()));
break;
case IDBKey::StringType:
stringValue = key->string();
break;
case IDBKey::DateType:
numberValue = key->date();
break;
case IDBKey::NumberType:
numberValue = key->number();
break;
case IDBKey::MaxType:
case IDBKey::MinType:
break;
}
}
PassRefPtr<IDBKey> IDBKeyData::maybeCreateIDBKey() const
{
if (isNull)
return nullptr;
switch (type) {
case IDBKey::InvalidType:
return IDBKey::createInvalid();
case IDBKey::ArrayType:
{
IDBKey::KeyArray array;
for (auto& keyData : arrayValue) {
array.append(keyData.maybeCreateIDBKey());
ASSERT(array.last());
}
return IDBKey::createArray(array);
}
case IDBKey::StringType:
return IDBKey::createString(stringValue);
case IDBKey::DateType:
return IDBKey::createDate(numberValue);
case IDBKey::NumberType:
return IDBKey::createNumber(numberValue);
case IDBKey::MaxType:
case IDBKey::MinType:
ASSERT_NOT_REACHED();
return nullptr;
}
ASSERT_NOT_REACHED();
return nullptr;
}
IDBKeyData IDBKeyData::isolatedCopy() const
{
IDBKeyData result;
result.type = type;
result.isNull = isNull;
switch (type) {
case IDBKey::InvalidType:
return result;
case IDBKey::ArrayType:
for (auto& key : arrayValue)
result.arrayValue.append(key.isolatedCopy());
return result;
case IDBKey::StringType:
result.stringValue = stringValue.isolatedCopy();
return result;
case IDBKey::DateType:
case IDBKey::NumberType:
result.numberValue = numberValue;
return result;
case IDBKey::MaxType:
case IDBKey::MinType:
return result;
}
ASSERT_NOT_REACHED();
return result;
}
void IDBKeyData::encode(KeyedEncoder& encoder) const
{
encoder.encodeBool("null", isNull);
if (isNull)
return;
encoder.encodeEnum("type", type);
switch (type) {
case IDBKey::InvalidType:
return;
case IDBKey::ArrayType:
encoder.encodeObjects("array", arrayValue.begin(), arrayValue.end(), [](KeyedEncoder& encoder, const IDBKeyData& key) {
key.encode(encoder);
});
return;
case IDBKey::StringType:
encoder.encodeString("string", stringValue);
return;
case IDBKey::DateType:
case IDBKey::NumberType:
encoder.encodeDouble("number", numberValue);
return;
case IDBKey::MaxType:
case IDBKey::MinType:
return;
}
ASSERT_NOT_REACHED();
}
bool IDBKeyData::decode(KeyedDecoder& decoder, IDBKeyData& result)
{
if (!decoder.decodeBool("null", result.isNull))
return false;
if (result.isNull)
return true;
auto enumFunction = [](int64_t value) {
return value == IDBKey::MaxType
|| value == IDBKey::InvalidType
|| value == IDBKey::ArrayType
|| value == IDBKey::StringType
|| value == IDBKey::DateType
|| value == IDBKey::NumberType
|| value == IDBKey::MinType;
};
if (!decoder.decodeEnum("type", result.type, enumFunction))
return false;
if (result.type == IDBKey::InvalidType)
return true;
if (result.type == IDBKey::MaxType)
return true;
if (result.type == IDBKey::MinType)
return true;
if (result.type == IDBKey::StringType)
return decoder.decodeString("string", result.stringValue);
if (result.type == IDBKey::NumberType || result.type == IDBKey::DateType)
return decoder.decodeDouble("number", result.numberValue);
ASSERT(result.type == IDBKey::ArrayType);
auto arrayFunction = [](KeyedDecoder& decoder, IDBKeyData& result) {
return decode(decoder, result);
};
result.arrayValue.clear();
return decoder.decodeObjects("array", result.arrayValue, arrayFunction);
}
int IDBKeyData::compare(const IDBKeyData& other) const
{
if (type == IDBKey::InvalidType) {
if (other.type != IDBKey::InvalidType)
return -1;
if (other.type == IDBKey::InvalidType)
return 0;
} else if (other.type == IDBKey::InvalidType)
return 1;
if (type != other.type)
return type < other.type ? 1 : -1;
switch (type) {
case IDBKey::InvalidType:
ASSERT_NOT_REACHED();
return 0;
case IDBKey::ArrayType:
for (size_t i = 0; i < arrayValue.size() && i < other.arrayValue.size(); ++i) {
if (int result = arrayValue[i].compare(other.arrayValue[i]))
return result;
}
if (arrayValue.size() < other.arrayValue.size())
return -1;
if (arrayValue.size() > other.arrayValue.size())
return 1;
return 0;
case IDBKey::StringType:
return codePointCompare(stringValue, other.stringValue);
case IDBKey::DateType:
case IDBKey::NumberType:
if (numberValue == other.numberValue)
return 0;
return numberValue > other.numberValue ? 1 : -1;
case IDBKey::MaxType:
case IDBKey::MinType:
return 0;
}
ASSERT_NOT_REACHED();
return 0;
}
#ifndef NDEBUG
String IDBKeyData::loggingString() const
{
if (isNull)
return "<null>";
switch (type) {
case IDBKey::InvalidType:
return "<invalid>";
case IDBKey::ArrayType:
{
StringBuilder result;
result.appendLiteral("<array> - { ");
for (size_t i = 0; i < arrayValue.size(); ++i) {
result.append(arrayValue[i].loggingString());
if (i < arrayValue.size() - 1)
result.appendLiteral(", ");
}
result.appendLiteral(" }");
return result.toString();
}
case IDBKey::StringType:
return "<string> - " + stringValue;
case IDBKey::DateType:
return String::format("Date type - %f", numberValue);
case IDBKey::NumberType:
return String::format("<number> - %f", numberValue);
case IDBKey::MaxType:
return "<maximum>";
case IDBKey::MinType:
return "<minimum>";
default:
return String();
}
ASSERT_NOT_REACHED();
}
#endif
void IDBKeyData::setArrayValue(const Vector<IDBKeyData>& value)
{
*this = IDBKeyData();
arrayValue = value;
type = IDBKey::ArrayType;
isNull = false;
}
void IDBKeyData::setStringValue(const String& value)
{
*this = IDBKeyData();
stringValue = value;
type = IDBKey::StringType;
isNull = false;
}
void IDBKeyData::setDateValue(double value)
{
*this = IDBKeyData();
numberValue = value;
type = IDBKey::DateType;
isNull = false;
}
void IDBKeyData::setNumberValue(double value)
{
*this = IDBKeyData();
numberValue = value;
type = IDBKey::NumberType;
isNull = false;
}
}
#endif // ENABLE(INDEXED_DATABASE)