From ae4b64b198a143240aa5dd1e202e5016abfdae71 Mon Sep 17 00:00:00 2001 From: Christian Mollekopf Date: Thu, 8 Dec 2016 13:18:19 +0100 Subject: Wrap references in a Reerence type. This allows us to make sure that references are not taken out of context (the resource). Because we need to use the type-specific accessors more we also ran into a problem that we cannot "downcast" a reference with the change recording still working, for that we have the cast() operator now. --- common/domain/applicationdomaintype.cpp | 35 ++++++++++++++----- common/domain/applicationdomaintype.h | 61 +++++++++++++++++++++++++++++---- 2 files changed, 81 insertions(+), 15 deletions(-) (limited to 'common/domain') diff --git a/common/domain/applicationdomaintype.cpp b/common/domain/applicationdomaintype.cpp index a655871..f00f3ed 100644 --- a/common/domain/applicationdomaintype.cpp +++ b/common/domain/applicationdomaintype.cpp @@ -31,7 +31,16 @@ namespace ApplicationDomain { constexpr const char *Mail::ThreadId::name; -void copyBuffer(Sink::ApplicationDomain::BufferAdaptor &buffer, Sink::ApplicationDomain::BufferAdaptor &memoryAdaptor, const QList &properties, bool copyBlobs) +int foo = [] { + QMetaType::registerEqualsComparator(); + QMetaType::registerDebugStreamOperator(); + QMetaType::registerConverter(); + QMetaType::registerDebugStreamOperator(); + QMetaType::registerDebugStreamOperator(); + return 0; +}(); + +void copyBuffer(Sink::ApplicationDomain::BufferAdaptor &buffer, Sink::ApplicationDomain::BufferAdaptor &memoryAdaptor, const QList &properties, bool copyBlobs, bool pruneReferences) { auto propertiesToCopy = properties; if (properties.isEmpty()) { @@ -44,6 +53,8 @@ void copyBuffer(Sink::ApplicationDomain::BufferAdaptor &buffer, Sink::Applicatio auto newPath = oldPath + "copy"; QFile::copy(oldPath, newPath); memoryAdaptor.setProperty(property, QVariant::fromValue(BLOB{newPath})); + } else if (pruneReferences && value.canConvert()) { + continue; } else { memoryAdaptor.setProperty(property, value); } @@ -51,14 +62,16 @@ void copyBuffer(Sink::ApplicationDomain::BufferAdaptor &buffer, Sink::Applicatio } ApplicationDomainType::ApplicationDomainType() - :mAdaptor(new MemoryBufferAdaptor()) + :mAdaptor(new MemoryBufferAdaptor()), + mChangeSet(new QSet()) { } ApplicationDomainType::ApplicationDomainType(const QByteArray &resourceInstanceIdentifier) :mAdaptor(new MemoryBufferAdaptor()), - mResourceInstanceIdentifier(resourceInstanceIdentifier) + mResourceInstanceIdentifier(resourceInstanceIdentifier), + mChangeSet(new QSet()) { } @@ -67,11 +80,13 @@ ApplicationDomainType::ApplicationDomainType(const QByteArray &resourceInstanceI : mAdaptor(adaptor), mResourceInstanceIdentifier(resourceInstanceIdentifier), mIdentifier(identifier), - mRevision(revision) + mRevision(revision), + mChangeSet(new QSet()) { } ApplicationDomainType::ApplicationDomainType(const ApplicationDomainType &other) + : mChangeSet(new QSet()) { *this = other; } @@ -79,7 +94,9 @@ ApplicationDomainType::ApplicationDomainType(const ApplicationDomainType &other) ApplicationDomainType& ApplicationDomainType::operator=(const ApplicationDomainType &other) { mAdaptor = other.mAdaptor; - mChangeSet = other.mChangeSet; + if (other.mChangeSet) { + *mChangeSet = *other.mChangeSet; + } mResourceInstanceIdentifier = other.mResourceInstanceIdentifier; mIdentifier = other.mIdentifier; mRevision = other.mRevision; @@ -110,7 +127,7 @@ QVariant ApplicationDomainType::getProperty(const QByteArray &key) const void ApplicationDomainType::setProperty(const QByteArray &key, const QVariant &value) { Q_ASSERT(mAdaptor); - mChangeSet.insert(key); + mChangeSet->insert(key); mAdaptor->setProperty(key, value); } @@ -122,7 +139,7 @@ void ApplicationDomainType::setResource(const QByteArray &identifier) void ApplicationDomainType::setProperty(const QByteArray &key, const ApplicationDomainType &value) { Q_ASSERT(!value.identifier().isEmpty()); - setProperty(key, value.identifier()); + setProperty(key, QVariant::fromValue(Reference{value.identifier()})); } QByteArray ApplicationDomainType::getBlobProperty(const QByteArray &key) const @@ -152,12 +169,12 @@ void ApplicationDomainType::setBlobProperty(const QByteArray &key, const QByteAr void ApplicationDomainType::setChangedProperties(const QSet &changeset) { - mChangeSet = changeset; + *mChangeSet = changeset; } QByteArrayList ApplicationDomainType::changedProperties() const { - return mChangeSet.toList(); + return mChangeSet->toList(); } QByteArrayList ApplicationDomainType::availableProperties() const diff --git a/common/domain/applicationdomaintype.h b/common/domain/applicationdomaintype.h index 21e42cf..1c0f208 100644 --- a/common/domain/applicationdomaintype.h +++ b/common/domain/applicationdomaintype.h @@ -73,12 +73,12 @@ #define SINK_REFERENCE_PROPERTY(TYPE, NAME, LOWERCASENAME) \ struct NAME { \ static constexpr const char *name = #LOWERCASENAME; \ - typedef QByteArray Type; \ + typedef Reference Type; \ typedef ApplicationDomain::TYPE ReferenceType; \ }; \ void set##NAME(const ApplicationDomain::TYPE &value) { setProperty(NAME::name, value); } \ - void set##NAME(const QByteArray &value) { setProperty(NAME::name, QVariant::fromValue(value)); } \ - QByteArray get##NAME() const { return getProperty(NAME::name).value(); } \ + void set##NAME(const QByteArray &value) { setProperty(NAME::name, QVariant::fromValue(Reference{value})); } \ + QByteArray get##NAME() const { return getProperty(NAME::name).value().value; } \ #define SINK_INDEX_PROPERTY(TYPE, NAME, LOWERCASENAME) \ struct NAME { \ @@ -102,7 +102,27 @@ struct BLOB { QString value; }; -void copyBuffer(Sink::ApplicationDomain::BufferAdaptor &buffer, Sink::ApplicationDomain::BufferAdaptor &memoryAdaptor, const QList &properties, bool copyBlobs); +/** + * Internal type. + * + * Represents a reference to another entity in the same resource. + */ +struct Reference { + Reference() = default; + Reference(const Reference &) = default; + Reference(const QByteArray &id) : value(id) {}; + Reference(const char *id) : value(id) {}; + ~Reference() = default; + bool operator==(const Reference &other) const { + return value == other.value; + } + operator QByteArray() const { + return value; + } + QByteArray value; +}; + +void copyBuffer(Sink::ApplicationDomain::BufferAdaptor &buffer, Sink::ApplicationDomain::BufferAdaptor &memoryAdaptor, const QList &properties, bool copyBlobs, bool pruneReferences); /** * The domain type interface has two purposes: @@ -121,6 +141,14 @@ public: ApplicationDomainType(const ApplicationDomainType &other); ApplicationDomainType& operator=(const ApplicationDomainType &other); + template + DomainType cast() { + static_assert(std::is_base_of::value, "You can only cast to base classes of ApplicationDomainType."); + DomainType t = *this; + t.mChangeSet = mChangeSet; + return t; + } + /** * Returns an in memory representation of the same entity. */ @@ -140,7 +168,7 @@ public: { auto memoryAdaptor = QSharedPointer::create(); Q_ASSERT(domainType.mAdaptor); - copyBuffer(*(domainType.mAdaptor), *memoryAdaptor, properties, true); + copyBuffer(*(domainType.mAdaptor), *memoryAdaptor, properties, true, true); return QSharedPointer::create(QByteArray{}, QByteArray{}, 0, memoryAdaptor); } @@ -195,7 +223,7 @@ public: private: friend QDebug operator<<(QDebug, const ApplicationDomainType &); QSharedPointer mAdaptor; - QSet mChangeSet; + QSharedPointer> mChangeSet; /* * Each domain object needs to store the resource, identifier, revision triple so we can link back to the storage location. */ @@ -223,6 +251,19 @@ inline QDebug operator<< (QDebug d, const ApplicationDomainType &type) return d; } +inline QDebug operator<< (QDebug d, const Reference &ref) +{ + d << ref.value; + return d; +} + +inline QDebug operator<< (QDebug d, const BLOB &blob) +{ + d << blob.value; + return d; +} + + struct SINK_EXPORT SinkAccount : public ApplicationDomainType { typedef QSharedPointer Ptr; explicit SinkAccount(const QByteArray &resourceInstanceIdentifier, const QByteArray &identifier, qint64 revision, const QSharedPointer &adaptor); @@ -318,6 +359,13 @@ struct SINK_EXPORT Mail : public Entity { SINK_INDEX_PROPERTY(QByteArray, ThreadId, threadId); }; +inline QDebug operator<< (QDebug d, const Mail::Contact &c) +{ + d << "Contact(" << c.name << ", " << c.emailAddress << ")"; + return d; +} + + /** * The status of an account or resource. * @@ -454,3 +502,4 @@ Q_DECLARE_METATYPE(Sink::ApplicationDomain::Mail::Contact) Q_DECLARE_METATYPE(Sink::ApplicationDomain::Error) Q_DECLARE_METATYPE(Sink::ApplicationDomain::Progress) Q_DECLARE_METATYPE(Sink::ApplicationDomain::BLOB) +Q_DECLARE_METATYPE(Sink::ApplicationDomain::Reference) -- cgit v1.2.3