Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
ValueHash.cpp 6.38 KiB
#include "ValueHash.h"

#include <QCryptographicHash>
#include <QJsonArray>
#include <QJsonObject>
#include <QCborArray>
#include <QCborMap>

using namespace knowCore;

struct ValueHash::Private : public QSharedData
{
  QHash<QString, Value> values;
};

ValueHash::ValueHash() : d(new Private)
{
}

ValueHash::ValueHash(std::initializer_list<std::pair<QString, Value> > _list) : ValueHash(QHash<QString, Value>(_list))
{
}

ValueHash::ValueHash(const QHash<QString, Value>& _values) : d(new Private)
{
  d->values = _values;
}

ValueHash::ValueHash(const ValueHash& _rhs) : d(_rhs.d)
{
}

ValueHash ValueHash::operator=(const ValueHash& _rhs)
{
  d = _rhs.d;
  return *this;
}

ValueHash::~ValueHash()
{
}

int ValueHash::size() const
{
  return d->values.size();
}

Value ValueHash::value(const QString& _key) const
{
  return d->values.value(_key);
}

bool ValueHash::contains(const QString& _key) const
{
  return d->values.contains(_key);
}

bool ValueHash::operator==(const ValueHash& _rhs) const
{
  return d->values == _rhs.d->values;
}

bool ValueHash::operator==(const QHash<QString, Value>& _rhs) const
{
  return d->values == _rhs;
}

ReturnValue<QByteArray> ValueHash::md5() const
{
  QCryptographicHash hash(QCryptographicHash::Md5);
  for(const Value& value : d->values)
  {
    KNOWCORE_RETURN_VALUE_TRY(value_md5, value.md5());
    hash.addData(value_md5);
  }
  return kCrvSuccess(hash.result());
}

#define DATATYPE_KEY  u8"datatype"_kCs
#define KEY_KEY       u8"key"_kCs
#define VALUE_KEY     u8"value"_kCs

ReturnValue<QJsonValue> ValueHash::toJsonValue(const SerialisationContexts& _contexts) const
{
  QJsonArray array;
  for(auto it = d->values.begin(); it != d->values.end(); ++it)
  {
    KNOWCORE_RETURN_VALUE_TRY(value_json, it.value().toJsonValue(_contexts));
    QJsonObject object;
    object[KEY_KEY] = it.key();
    object[DATATYPE_KEY] = (QString)it.value().datatype();
    object[VALUE_KEY] = value_json;
    array.append(object);
  }
  return kCrvSuccess(array);
}

ReturnValue<ValueHash> ValueHash::fromJsonValue(const QJsonValue& _json_value, const DeserialisationContexts& _context)
{
  if(_json_value.isArray())
  {
    QHash<QString, Value> values;
    QJsonArray json_array = _json_value.toArray();
    for(int i = 0; i < json_array.size(); ++i)
    {
      QJsonValue json_value = json_array.at(i);
      if(json_value.isObject())
      {
        QJsonObject obj = json_value.toObject();
        Uri datatype = obj.value(DATATYPE_KEY).toString();
        KNOWCORE_RETURN_VALUE_TRY(value, Value::fromJsonValue(datatype, obj.value(VALUE_KEY), _context));
        values[obj.value(KEY_KEY).toString()] = value;
      } else {
        return kCrvError("Expected object got '{}' when parsing ValueHash '{}'", json_value, _json_value);
      }
    }
    return kCrvSuccess(values);
  } else {
    return kCrvError("Expect array got '{}'", _json_value);
  }
}

ReturnValue<QCborValue> ValueHash::toCborValue(const SerialisationContexts& _contexts) const
{
  QCborArray array;
  for(auto it = d->values.begin(); it != d->values.end(); ++it)
  {
    KNOWCORE_RETURN_VALUE_TRY(value_cbor, it.value().toCborValue(_contexts));
    QCborMap map;
    map[KEY_KEY] = it.key();
    map[DATATYPE_KEY] = (QString)it.value().datatype();
    map[VALUE_KEY] = value_cbor;
    array.append(map);
  }
  return kCrvSuccess(array);
}

ReturnValue<ValueHash> ValueHash::fromCborValue(const QCborValue& _cbor_value, const DeserialisationContexts& _contexts)
{
  if(_cbor_value.isArray())
  {
    QHash<QString, Value> values;
    QCborArray cbor_array = _cbor_value.toArray();
    for(int i = 0; i < cbor_array.size(); ++i)
    {
      QCborValue cbor_value = cbor_array.at(i);
      if(cbor_value.isMap())
      {
        QCborMap obj = cbor_value.toMap();
        Uri datatype = obj.value(DATATYPE_KEY).toString();
        KNOWCORE_RETURN_VALUE_TRY(value, Value::fromCborValue(datatype, obj.value(VALUE_KEY), _contexts));
        values[obj.value(KEY_KEY).toString()] = value;
      } else {
        return kCrvError("Expected object got '{}' when parsing ValueHash '{}'", cbor_value, _cbor_value);
      }
    }
    return kCrvSuccess(values);
  } else {
    return kCrvError("Expect array got '{}'", _cbor_value);
  }
}

ReturnValue<QString> ValueHash::printable() const
{
  QStringList strings;
  for(const Value& v : d->values)
  {
    KNOWCORE_RETURN_VALUE_TRY(str, v.printable());
    strings.append(str);
  }
  return kCrvSuccess(clog_qt::qformat("[{}]", ", "));
}

QHash<QString, Value> ValueHash::hash() const
{
  return d->values;
}

ReturnValue<void> ValueHash::checkContainsOnly(const knowCore::Uri& _uri) const
{
  for(const Value& value : d->values)
  {
    if(value.datatype() != _uri)
    {
      return kCrvError("Invalid type '{}' in list, expected: '{}'", value.datatype(), _uri);
    }
  }
  return kCrvSuccess();
}

#include <knowCore/Uris/askcore_types.h>
#include "MetaTypeImplementation.h"

KNOWCORE_DEFINE_METATYPE_START_IMPLEMENTATION(ValueHash)
  ReturnValue<QByteArray> md5(const ValueHash& _value) const override
  {
    return _value.md5();
  }
  ReturnValue<QJsonValue> toJsonValue(const ValueHash& _value, const SerialisationContexts& _contexts) const override
  {
    return _value.toJsonValue(_contexts);
  }
  ReturnValue<void> fromJsonValue(ValueHash* _value, const QJsonValue& _json_value, const DeserialisationContexts& _contexts) const override
  {
    return kCrvTryAssign(_value, ValueHash::fromJsonValue(_json_value, _contexts));
  }
  ReturnValue<QCborValue> toCborValue(const ValueHash& _value, const SerialisationContexts& _contexts) const override
  {
    return _value.toCborValue(_contexts);
  }
  ReturnValue<void> fromCborValue(ValueHash* _value, const QCborValue& _cbor_value, const DeserialisationContexts& _contexts) const override
  {
    return kCrvTryAssign(_value, ValueHash::fromCborValue(_cbor_value, _contexts));
  }
  ReturnValue<QString> printable(const ValueHash& _value) const override
  {
    return _value.printable();
  }
  ReturnValue<QString> toRdfLiteral(const ValueHash& _value, const SerialisationContexts& _contexts) const override
  {
    return toJsonString(_value, _contexts);
  }
  ReturnValue<void> fromRdfLiteral(ValueHash* _value, const QString& _serialised, const DeserialisationContexts& _contexts) const override
  {
    return fromJsonString(_value, _serialised, _contexts);
  }
KNOWCORE_DEFINE_METATYPE_FINISH_IMPLEMENTATION(ValueHash)

KNOWCORE_DEFINE_METATYPE(ValueHash, Uris::askcore_types::valuehash, MetaTypeTraits::None)