summaryrefslogtreecommitdiffstats
path: root/common/domain
diff options
context:
space:
mode:
authorChristian Mollekopf <chrigi_1@fastmail.fm>2016-12-08 13:18:19 +0100
committerChristian Mollekopf <chrigi_1@fastmail.fm>2016-12-08 13:18:19 +0100
commitae4b64b198a143240aa5dd1e202e5016abfdae71 (patch)
tree5d9d58a512ebc60c44637d11c9424f67a02887e8 /common/domain
parentf425c2070131161dc11bcf70e35f8d1848cadb65 (diff)
downloadsink-ae4b64b198a143240aa5dd1e202e5016abfdae71.tar.gz
sink-ae4b64b198a143240aa5dd1e202e5016abfdae71.zip
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<T>() operator now.
Diffstat (limited to 'common/domain')
-rw-r--r--common/domain/applicationdomaintype.cpp35
-rw-r--r--common/domain/applicationdomaintype.h61
2 files changed, 81 insertions, 15 deletions
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 {
31 31
32constexpr const char *Mail::ThreadId::name; 32constexpr const char *Mail::ThreadId::name;
33 33
34void copyBuffer(Sink::ApplicationDomain::BufferAdaptor &buffer, Sink::ApplicationDomain::BufferAdaptor &memoryAdaptor, const QList<QByteArray> &properties, bool copyBlobs) 34int foo = [] {
35 QMetaType::registerEqualsComparator<Reference>();
36 QMetaType::registerDebugStreamOperator<Reference>();
37 QMetaType::registerConverter<Reference, QByteArray>();
38 QMetaType::registerDebugStreamOperator<BLOB>();
39 QMetaType::registerDebugStreamOperator<Mail::Contact>();
40 return 0;
41}();
42
43void copyBuffer(Sink::ApplicationDomain::BufferAdaptor &buffer, Sink::ApplicationDomain::BufferAdaptor &memoryAdaptor, const QList<QByteArray> &properties, bool copyBlobs, bool pruneReferences)
35{ 44{
36 auto propertiesToCopy = properties; 45 auto propertiesToCopy = properties;
37 if (properties.isEmpty()) { 46 if (properties.isEmpty()) {
@@ -44,6 +53,8 @@ void copyBuffer(Sink::ApplicationDomain::BufferAdaptor &buffer, Sink::Applicatio
44 auto newPath = oldPath + "copy"; 53 auto newPath = oldPath + "copy";
45 QFile::copy(oldPath, newPath); 54 QFile::copy(oldPath, newPath);
46 memoryAdaptor.setProperty(property, QVariant::fromValue(BLOB{newPath})); 55 memoryAdaptor.setProperty(property, QVariant::fromValue(BLOB{newPath}));
56 } else if (pruneReferences && value.canConvert<Reference>()) {
57 continue;
47 } else { 58 } else {
48 memoryAdaptor.setProperty(property, value); 59 memoryAdaptor.setProperty(property, value);
49 } 60 }
@@ -51,14 +62,16 @@ void copyBuffer(Sink::ApplicationDomain::BufferAdaptor &buffer, Sink::Applicatio
51} 62}
52 63
53ApplicationDomainType::ApplicationDomainType() 64ApplicationDomainType::ApplicationDomainType()
54 :mAdaptor(new MemoryBufferAdaptor()) 65 :mAdaptor(new MemoryBufferAdaptor()),
66 mChangeSet(new QSet<QByteArray>())
55{ 67{
56 68
57} 69}
58 70
59ApplicationDomainType::ApplicationDomainType(const QByteArray &resourceInstanceIdentifier) 71ApplicationDomainType::ApplicationDomainType(const QByteArray &resourceInstanceIdentifier)
60 :mAdaptor(new MemoryBufferAdaptor()), 72 :mAdaptor(new MemoryBufferAdaptor()),
61 mResourceInstanceIdentifier(resourceInstanceIdentifier) 73 mResourceInstanceIdentifier(resourceInstanceIdentifier),
74 mChangeSet(new QSet<QByteArray>())
62{ 75{
63 76
64} 77}
@@ -67,11 +80,13 @@ ApplicationDomainType::ApplicationDomainType(const QByteArray &resourceInstanceI
67 : mAdaptor(adaptor), 80 : mAdaptor(adaptor),
68 mResourceInstanceIdentifier(resourceInstanceIdentifier), 81 mResourceInstanceIdentifier(resourceInstanceIdentifier),
69 mIdentifier(identifier), 82 mIdentifier(identifier),
70 mRevision(revision) 83 mRevision(revision),
84 mChangeSet(new QSet<QByteArray>())
71{ 85{
72} 86}
73 87
74ApplicationDomainType::ApplicationDomainType(const ApplicationDomainType &other) 88ApplicationDomainType::ApplicationDomainType(const ApplicationDomainType &other)
89 : mChangeSet(new QSet<QByteArray>())
75{ 90{
76 *this = other; 91 *this = other;
77} 92}
@@ -79,7 +94,9 @@ ApplicationDomainType::ApplicationDomainType(const ApplicationDomainType &other)
79ApplicationDomainType& ApplicationDomainType::operator=(const ApplicationDomainType &other) 94ApplicationDomainType& ApplicationDomainType::operator=(const ApplicationDomainType &other)
80{ 95{
81 mAdaptor = other.mAdaptor; 96 mAdaptor = other.mAdaptor;
82 mChangeSet = other.mChangeSet; 97 if (other.mChangeSet) {
98 *mChangeSet = *other.mChangeSet;
99 }
83 mResourceInstanceIdentifier = other.mResourceInstanceIdentifier; 100 mResourceInstanceIdentifier = other.mResourceInstanceIdentifier;
84 mIdentifier = other.mIdentifier; 101 mIdentifier = other.mIdentifier;
85 mRevision = other.mRevision; 102 mRevision = other.mRevision;
@@ -110,7 +127,7 @@ QVariant ApplicationDomainType::getProperty(const QByteArray &key) const
110void ApplicationDomainType::setProperty(const QByteArray &key, const QVariant &value) 127void ApplicationDomainType::setProperty(const QByteArray &key, const QVariant &value)
111{ 128{
112 Q_ASSERT(mAdaptor); 129 Q_ASSERT(mAdaptor);
113 mChangeSet.insert(key); 130 mChangeSet->insert(key);
114 mAdaptor->setProperty(key, value); 131 mAdaptor->setProperty(key, value);
115} 132}
116 133
@@ -122,7 +139,7 @@ void ApplicationDomainType::setResource(const QByteArray &identifier)
122void ApplicationDomainType::setProperty(const QByteArray &key, const ApplicationDomainType &value) 139void ApplicationDomainType::setProperty(const QByteArray &key, const ApplicationDomainType &value)
123{ 140{
124 Q_ASSERT(!value.identifier().isEmpty()); 141 Q_ASSERT(!value.identifier().isEmpty());
125 setProperty(key, value.identifier()); 142 setProperty(key, QVariant::fromValue(Reference{value.identifier()}));
126} 143}
127 144
128QByteArray ApplicationDomainType::getBlobProperty(const QByteArray &key) const 145QByteArray ApplicationDomainType::getBlobProperty(const QByteArray &key) const
@@ -152,12 +169,12 @@ void ApplicationDomainType::setBlobProperty(const QByteArray &key, const QByteAr
152 169
153void ApplicationDomainType::setChangedProperties(const QSet<QByteArray> &changeset) 170void ApplicationDomainType::setChangedProperties(const QSet<QByteArray> &changeset)
154{ 171{
155 mChangeSet = changeset; 172 *mChangeSet = changeset;
156} 173}
157 174
158QByteArrayList ApplicationDomainType::changedProperties() const 175QByteArrayList ApplicationDomainType::changedProperties() const
159{ 176{
160 return mChangeSet.toList(); 177 return mChangeSet->toList();
161} 178}
162 179
163QByteArrayList ApplicationDomainType::availableProperties() const 180QByteArrayList 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 @@
73#define SINK_REFERENCE_PROPERTY(TYPE, NAME, LOWERCASENAME) \ 73#define SINK_REFERENCE_PROPERTY(TYPE, NAME, LOWERCASENAME) \
74 struct NAME { \ 74 struct NAME { \
75 static constexpr const char *name = #LOWERCASENAME; \ 75 static constexpr const char *name = #LOWERCASENAME; \
76 typedef QByteArray Type; \ 76 typedef Reference Type; \
77 typedef ApplicationDomain::TYPE ReferenceType; \ 77 typedef ApplicationDomain::TYPE ReferenceType; \
78 }; \ 78 }; \
79 void set##NAME(const ApplicationDomain::TYPE &value) { setProperty(NAME::name, value); } \ 79 void set##NAME(const ApplicationDomain::TYPE &value) { setProperty(NAME::name, value); } \
80 void set##NAME(const QByteArray &value) { setProperty(NAME::name, QVariant::fromValue(value)); } \ 80 void set##NAME(const QByteArray &value) { setProperty(NAME::name, QVariant::fromValue(Reference{value})); } \
81 QByteArray get##NAME() const { return getProperty(NAME::name).value<QByteArray>(); } \ 81 QByteArray get##NAME() const { return getProperty(NAME::name).value<Reference>().value; } \
82 82
83#define SINK_INDEX_PROPERTY(TYPE, NAME, LOWERCASENAME) \ 83#define SINK_INDEX_PROPERTY(TYPE, NAME, LOWERCASENAME) \
84 struct NAME { \ 84 struct NAME { \
@@ -102,7 +102,27 @@ struct BLOB {
102 QString value; 102 QString value;
103}; 103};
104 104
105void copyBuffer(Sink::ApplicationDomain::BufferAdaptor &buffer, Sink::ApplicationDomain::BufferAdaptor &memoryAdaptor, const QList<QByteArray> &properties, bool copyBlobs); 105/**
106 * Internal type.
107 *
108 * Represents a reference to another entity in the same resource.
109 */
110struct Reference {
111 Reference() = default;
112 Reference(const Reference &) = default;
113 Reference(const QByteArray &id) : value(id) {};
114 Reference(const char *id) : value(id) {};
115 ~Reference() = default;
116 bool operator==(const Reference &other) const {
117 return value == other.value;
118 }
119 operator QByteArray() const {
120 return value;
121 }
122 QByteArray value;
123};
124
125void copyBuffer(Sink::ApplicationDomain::BufferAdaptor &buffer, Sink::ApplicationDomain::BufferAdaptor &memoryAdaptor, const QList<QByteArray> &properties, bool copyBlobs, bool pruneReferences);
106 126
107/** 127/**
108 * The domain type interface has two purposes: 128 * The domain type interface has two purposes:
@@ -121,6 +141,14 @@ public:
121 ApplicationDomainType(const ApplicationDomainType &other); 141 ApplicationDomainType(const ApplicationDomainType &other);
122 ApplicationDomainType& operator=(const ApplicationDomainType &other); 142 ApplicationDomainType& operator=(const ApplicationDomainType &other);
123 143
144 template <typename DomainType>
145 DomainType cast() {
146 static_assert(std::is_base_of<ApplicationDomainType, DomainType>::value, "You can only cast to base classes of ApplicationDomainType.");
147 DomainType t = *this;
148 t.mChangeSet = mChangeSet;
149 return t;
150 }
151
124 /** 152 /**
125 * Returns an in memory representation of the same entity. 153 * Returns an in memory representation of the same entity.
126 */ 154 */
@@ -140,7 +168,7 @@ public:
140 { 168 {
141 auto memoryAdaptor = QSharedPointer<Sink::ApplicationDomain::MemoryBufferAdaptor>::create(); 169 auto memoryAdaptor = QSharedPointer<Sink::ApplicationDomain::MemoryBufferAdaptor>::create();
142 Q_ASSERT(domainType.mAdaptor); 170 Q_ASSERT(domainType.mAdaptor);
143 copyBuffer(*(domainType.mAdaptor), *memoryAdaptor, properties, true); 171 copyBuffer(*(domainType.mAdaptor), *memoryAdaptor, properties, true, true);
144 return QSharedPointer<DomainType>::create(QByteArray{}, QByteArray{}, 0, memoryAdaptor); 172 return QSharedPointer<DomainType>::create(QByteArray{}, QByteArray{}, 0, memoryAdaptor);
145 } 173 }
146 174
@@ -195,7 +223,7 @@ public:
195private: 223private:
196 friend QDebug operator<<(QDebug, const ApplicationDomainType &); 224 friend QDebug operator<<(QDebug, const ApplicationDomainType &);
197 QSharedPointer<BufferAdaptor> mAdaptor; 225 QSharedPointer<BufferAdaptor> mAdaptor;
198 QSet<QByteArray> mChangeSet; 226 QSharedPointer<QSet<QByteArray>> mChangeSet;
199 /* 227 /*
200 * Each domain object needs to store the resource, identifier, revision triple so we can link back to the storage location. 228 * Each domain object needs to store the resource, identifier, revision triple so we can link back to the storage location.
201 */ 229 */
@@ -223,6 +251,19 @@ inline QDebug operator<< (QDebug d, const ApplicationDomainType &type)
223 return d; 251 return d;
224} 252}
225 253
254inline QDebug operator<< (QDebug d, const Reference &ref)
255{
256 d << ref.value;
257 return d;
258}
259
260inline QDebug operator<< (QDebug d, const BLOB &blob)
261{
262 d << blob.value;
263 return d;
264}
265
266
226struct SINK_EXPORT SinkAccount : public ApplicationDomainType { 267struct SINK_EXPORT SinkAccount : public ApplicationDomainType {
227 typedef QSharedPointer<SinkAccount> Ptr; 268 typedef QSharedPointer<SinkAccount> Ptr;
228 explicit SinkAccount(const QByteArray &resourceInstanceIdentifier, const QByteArray &identifier, qint64 revision, const QSharedPointer<BufferAdaptor> &adaptor); 269 explicit SinkAccount(const QByteArray &resourceInstanceIdentifier, const QByteArray &identifier, qint64 revision, const QSharedPointer<BufferAdaptor> &adaptor);
@@ -318,6 +359,13 @@ struct SINK_EXPORT Mail : public Entity {
318 SINK_INDEX_PROPERTY(QByteArray, ThreadId, threadId); 359 SINK_INDEX_PROPERTY(QByteArray, ThreadId, threadId);
319}; 360};
320 361
362inline QDebug operator<< (QDebug d, const Mail::Contact &c)
363{
364 d << "Contact(" << c.name << ", " << c.emailAddress << ")";
365 return d;
366}
367
368
321/** 369/**
322 * The status of an account or resource. 370 * The status of an account or resource.
323 * 371 *
@@ -454,3 +502,4 @@ Q_DECLARE_METATYPE(Sink::ApplicationDomain::Mail::Contact)
454Q_DECLARE_METATYPE(Sink::ApplicationDomain::Error) 502Q_DECLARE_METATYPE(Sink::ApplicationDomain::Error)
455Q_DECLARE_METATYPE(Sink::ApplicationDomain::Progress) 503Q_DECLARE_METATYPE(Sink::ApplicationDomain::Progress)
456Q_DECLARE_METATYPE(Sink::ApplicationDomain::BLOB) 504Q_DECLARE_METATYPE(Sink::ApplicationDomain::BLOB)
505Q_DECLARE_METATYPE(Sink::ApplicationDomain::Reference)