1/*
2 This file is part of the syndication library
3 SPDX-FileCopyrightText: 2006 Frank Osterfeld <osterfeld@kde.org>
4
5 SPDX-License-Identifier: LGPL-2.0-or-later
6*/
7
8#include "model.h"
9#include "model_p.h"
10
11namespace Syndication
12{
13namespace RDF
14{
15long Model::ModelPrivate::idCounter = 0;
16
17Model::Model()
18 : d(new ModelPrivate)
19{
20}
21
22Model::Model(const Model &other)
23{
24 *this = other;
25}
26
27Model::~Model()
28{
29}
30
31Model &Model::operator=(const Model &other)
32{
33 d = other.d;
34 return *this;
35}
36
37bool Model::operator==(const Model &other) const
38{
39 return *d == *(other.d);
40}
41
42PropertyPtr Model::createProperty(const QString &uri)
43{
44 PropertyPtr prop;
45
46 if (d->properties.contains(key: uri)) {
47 prop = d->properties[uri];
48 } else {
49 prop = PropertyPtr(new Property(uri));
50 prop->setModel(*this);
51 // if there is a resource object with the same uri, replace
52 // the resource object by the new property object and reuse the id
53 if (d->resources.contains(key: uri)) {
54 prop->setId(d->resources[uri]->id());
55 }
56 d->addToHashes(node: prop);
57 }
58
59 return prop;
60}
61
62ResourcePtr Model::createResource(const QString &uri)
63{
64 ResourcePtr res;
65
66 if (d->resources.contains(key: uri)) {
67 res = d->resources[uri];
68 } else {
69 res = ResourcePtr(new Resource(uri));
70 res->setModel(*this);
71 d->addToHashes(node: res);
72 }
73
74 return res;
75}
76
77SequencePtr Model::createSequence(const QString &uri)
78{
79 SequencePtr seq;
80
81 if (d->sequences.contains(key: uri)) {
82 seq = d->sequences[uri];
83 } else {
84 seq = SequencePtr(new Sequence(uri));
85 seq->setModel(*this);
86 // if there is a resource object with the same uri, replace
87 // the resource object by the new sequence object and reuse the id
88 if (d->resources.contains(key: uri)) {
89 seq->setId(d->resources[uri]->id());
90 }
91
92 d->addToHashes(node: seq);
93 }
94
95 return seq;
96}
97
98LiteralPtr Model::createLiteral(const QString &text)
99{
100 LiteralPtr lit(new Literal(text));
101
102 d->addToHashes(node: lit);
103 return lit;
104}
105
106void Model::removeStatement(StatementPtr statement)
107{
108 removeStatement(subject: statement->subject(), predicate: statement->predicate(), object: statement->object());
109}
110
111void Model::removeStatement(ResourcePtr subject, PropertyPtr predicate, NodePtr object)
112{
113 /* clang-format off */
114 QString key = QStringLiteral("%1-%2-%3").arg(args: QString::number(subject->id()),
115 args: QString::number(predicate->id()),
116 args: QString::number(object->id()));
117 /* clang-format on */
118
119 d->removeFromHashes(key);
120}
121
122StatementPtr Model::addStatement(ResourcePtr subject, PropertyPtr predicate, NodePtr object)
123{
124 d->init(sharedThis: d);
125 ResourcePtr subjInternal = subject;
126
127 if (!d->nodes.contains(key: subjInternal->id())) {
128 subjInternal = ResourcePtr(subject->clone());
129 subjInternal->setModel(*this);
130 d->addToHashes(node: subjInternal);
131 }
132
133 PropertyPtr predInternal = predicate;
134
135 if (!d->nodes.contains(key: predInternal->id())) {
136 predInternal = PropertyPtr(predicate->clone());
137 predInternal->setModel(*this);
138 d->addToHashes(node: predInternal);
139 }
140
141 NodePtr objInternal = object;
142
143 if (!d->nodes.contains(key: objInternal->id())) {
144 objInternal = NodePtr(object->clone());
145 objInternal->setModel(*this);
146 d->addToHashes(node: objInternal);
147 }
148
149 // TODO: avoid duplicated stmts with literal objects!
150
151 /* clang-format off */
152 QString key = QStringLiteral("%1-%2-%3").arg(args: QString::number(subjInternal->id()),
153 args: QString::number(predInternal->id()),
154 args: QString::number(objInternal->id()));
155 /* clang-format on */
156
157 StatementPtr stmt;
158
159 if (!d->statements.contains(key)) {
160 stmt = StatementPtr(new Statement(subjInternal, predInternal, objInternal));
161 d->addToHashes(stmt, key);
162 } else {
163 stmt = d->statements[key];
164 }
165
166 return stmt;
167}
168
169bool Model::isEmpty() const
170{
171 return d->statements.isEmpty();
172}
173
174bool Model::resourceHasProperty(const Resource *resource, PropertyPtr property) const
175{
176 return d->resourceHasProperty(resource, property);
177}
178
179bool Model::ModelPrivate::resourceHasProperty(const Resource *resource, PropertyPtr property) const
180{
181 // resource unknown
182 if (!resources.contains(key: resource->uri())) {
183 return false;
184 }
185
186 const QList<StatementPtr> &stmts = stmtsBySubject[resource->uri()];
187
188 return std::any_of(first: stmts.cbegin(), last: stmts.cend(), pred: [&property](const StatementPtr &p) {
189 return *(p->predicate()) == *property;
190 });
191}
192
193StatementPtr Model::resourceProperty(const Resource *resource, PropertyPtr property) const
194{
195 return d->resourceProperty(resource, property);
196}
197
198StatementPtr Model::ModelPrivate::resourceProperty(const Resource *resource, PropertyPtr property) const
199{
200 const QList<StatementPtr> &stmts = stmtsBySubject[resource->uri()];
201 auto it = std::find_if(first: stmts.cbegin(), last: stmts.cend(), pred: [&property](const StatementPtr &p) {
202 return *(p->predicate()) == *property;
203 });
204 return it != stmts.cend() ? *it : nullStatement;
205}
206
207QList<StatementPtr> Model::resourceProperties(const Resource *resource, PropertyPtr property) const
208{
209 return d->resourceProperties(resource, property);
210}
211
212QList<StatementPtr> Model::ModelPrivate::resourceProperties(const Resource *resource, PropertyPtr property) const
213{
214 QList<StatementPtr> res;
215
216 const QList<StatementPtr> &stmts = stmtsBySubject[resource->uri()];
217 for (const auto &p : stmts) {
218 if (*(p->predicate()) == *property) {
219 res.append(t: p);
220 }
221 }
222
223 return res;
224}
225
226QList<StatementPtr> Model::statements() const
227{
228 return d->statements.values();
229}
230
231QString Model::debugInfo() const
232{
233 QString info;
234 for (const StatementPtr &stmtPtr : std::as_const(t&: d->statements)) {
235 info += QStringLiteral("<%1> <%2> ").arg(args: stmtPtr->subject()->uri(), args: stmtPtr->predicate()->uri());
236
237 if (stmtPtr->object()->isLiteral()) {
238 info += QStringLiteral("\"%1\"\n").arg(a: stmtPtr->asString());
239 } else {
240 info += QStringLiteral("<%1>\n").arg(a: stmtPtr->asResource()->uri());
241 }
242 }
243
244 return info;
245}
246
247QList<ResourcePtr> Model::resourcesWithType(ResourcePtr type) const
248{
249 QList<ResourcePtr> list;
250
251 for (const StatementPtr &stmtPtr : std::as_const(t&: d->statements)) {
252 if (*(stmtPtr->predicate()) == *(RDFVocab::self()->type()) //
253 && stmtPtr->object()->isResource() && *(dynamic_cast<Resource *>(stmtPtr->object().data())) == *type) {
254 list.append(t: stmtPtr->subject());
255 }
256 }
257
258 return list;
259}
260
261NodePtr Model::nodeByID(uint id) const
262{
263 return d->nodeByID(id);
264}
265
266NodePtr Model::ModelPrivate::nodeByID(uint _id) const
267{
268 if (!nodes.contains(key: _id)) {
269 return nullLiteral;
270 } else {
271 return nodes.value(key: _id);
272 }
273}
274
275ResourcePtr Model::resourceByID(uint id) const
276{
277 return d->resourceByID(id);
278}
279
280ResourcePtr Model::ModelPrivate::resourceByID(uint _id) const
281{
282 if (!nodes.contains(key: _id)) {
283 return nullResource;
284 } else {
285 NodePtr node = nodes.value(key: _id);
286 if (node->isResource()) {
287 return node.staticCast<Resource>();
288 } else {
289 return nullResource;
290 }
291 }
292}
293
294PropertyPtr Model::propertyByID(uint id) const
295{
296 return d->propertyByID(id);
297}
298
299PropertyPtr Model::ModelPrivate::propertyByID(uint _id) const
300{
301 if (!nodes.contains(key: _id)) {
302 return nullProperty;
303 } else {
304 NodePtr node = nodes.value(key: _id);
305 if (node->isProperty()) {
306 return node.staticCast<Property>();
307 } else {
308 return nullProperty;
309 }
310 }
311}
312
313LiteralPtr Model::literalByID(uint id) const
314{
315 return d->literalByID(id);
316}
317
318LiteralPtr Model::ModelPrivate::literalByID(uint _id) const
319{
320 if (!nodes.contains(key: _id)) {
321 return nullLiteral;
322 } else {
323 NodePtr node = nodes.value(key: _id);
324 if (node->isLiteral()) {
325 return node.staticCast<Literal>();
326 } else {
327 return nullLiteral;
328 }
329 }
330}
331
332} // namespace RDF
333} // namespace Syndication
334

source code of syndication/src/rdf/model.cpp