File indexing completed on 2024-04-21 04:01:02

0001 /*
0002     This file is part of the syndication library
0003     SPDX-FileCopyrightText: 2006 Frank Osterfeld <osterfeld@kde.org>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-or-later
0006 */
0007 
0008 #include "model.h"
0009 #include "model_p.h"
0010 
0011 namespace Syndication
0012 {
0013 namespace RDF
0014 {
0015 long Model::ModelPrivate::idCounter = 0;
0016 
0017 Model::Model()
0018     : d(new ModelPrivate)
0019 {
0020 }
0021 
0022 Model::Model(const Model &other)
0023 {
0024     *this = other;
0025 }
0026 
0027 Model::~Model()
0028 {
0029 }
0030 
0031 Model &Model::operator=(const Model &other)
0032 {
0033     d = other.d;
0034     return *this;
0035 }
0036 
0037 bool Model::operator==(const Model &other) const
0038 {
0039     return *d == *(other.d);
0040 }
0041 
0042 PropertyPtr Model::createProperty(const QString &uri)
0043 {
0044     PropertyPtr prop;
0045 
0046     if (d->properties.contains(uri)) {
0047         prop = d->properties[uri];
0048     } else {
0049         prop = PropertyPtr(new Property(uri));
0050         prop->setModel(*this);
0051         // if there is a resource object with the same uri, replace
0052         // the resource object by the new property object and reuse the id
0053         if (d->resources.contains(uri)) {
0054             prop->setId(d->resources[uri]->id());
0055         }
0056         d->addToHashes(prop);
0057     }
0058 
0059     return prop;
0060 }
0061 
0062 ResourcePtr Model::createResource(const QString &uri)
0063 {
0064     ResourcePtr res;
0065 
0066     if (d->resources.contains(uri)) {
0067         res = d->resources[uri];
0068     } else {
0069         res = ResourcePtr(new Resource(uri));
0070         res->setModel(*this);
0071         d->addToHashes(res);
0072     }
0073 
0074     return res;
0075 }
0076 
0077 SequencePtr Model::createSequence(const QString &uri)
0078 {
0079     SequencePtr seq;
0080 
0081     if (d->sequences.contains(uri)) {
0082         seq = d->sequences[uri];
0083     } else {
0084         seq = SequencePtr(new Sequence(uri));
0085         seq->setModel(*this);
0086         // if there is a resource object with the same uri, replace
0087         // the resource object by the new sequence object and reuse the id
0088         if (d->resources.contains(uri)) {
0089             seq->setId(d->resources[uri]->id());
0090         }
0091 
0092         d->addToHashes(seq);
0093     }
0094 
0095     return seq;
0096 }
0097 
0098 LiteralPtr Model::createLiteral(const QString &text)
0099 {
0100     LiteralPtr lit(new Literal(text));
0101 
0102     d->addToHashes(lit);
0103     return lit;
0104 }
0105 
0106 void Model::removeStatement(StatementPtr statement)
0107 {
0108     removeStatement(statement->subject(), statement->predicate(), statement->object());
0109 }
0110 
0111 void Model::removeStatement(ResourcePtr subject, PropertyPtr predicate, NodePtr object)
0112 {
0113     /* clang-format off */
0114     QString key = QStringLiteral("%1-%2-%3").arg(QString::number(subject->id()),
0115                                                  QString::number(predicate->id()),
0116                                                  QString::number(object->id()));
0117     /* clang-format on */
0118 
0119     d->removeFromHashes(key);
0120 }
0121 
0122 StatementPtr Model::addStatement(ResourcePtr subject, PropertyPtr predicate, NodePtr object)
0123 {
0124     d->init(d);
0125     ResourcePtr subjInternal = subject;
0126 
0127     if (!d->nodes.contains(subjInternal->id())) {
0128         subjInternal = ResourcePtr(subject->clone());
0129         subjInternal->setModel(*this);
0130         d->addToHashes(subjInternal);
0131     }
0132 
0133     PropertyPtr predInternal = predicate;
0134 
0135     if (!d->nodes.contains(predInternal->id())) {
0136         predInternal = PropertyPtr(predicate->clone());
0137         predInternal->setModel(*this);
0138         d->addToHashes(predInternal);
0139     }
0140 
0141     NodePtr objInternal = object;
0142 
0143     if (!d->nodes.contains(objInternal->id())) {
0144         objInternal = NodePtr(object->clone());
0145         objInternal->setModel(*this);
0146         d->addToHashes(objInternal);
0147     }
0148 
0149     // TODO: avoid duplicated stmts with literal objects!
0150 
0151     /* clang-format off */
0152     QString key = QStringLiteral("%1-%2-%3").arg(QString::number(subjInternal->id()),
0153                                                  QString::number(predInternal->id()),
0154                                                  QString::number(objInternal->id()));
0155     /* clang-format on */
0156 
0157     StatementPtr stmt;
0158 
0159     if (!d->statements.contains(key)) {
0160         stmt = StatementPtr(new Statement(subjInternal, predInternal, objInternal));
0161         d->addToHashes(stmt, key);
0162     } else {
0163         stmt = d->statements[key];
0164     }
0165 
0166     return stmt;
0167 }
0168 
0169 bool Model::isEmpty() const
0170 {
0171     return d->statements.isEmpty();
0172 }
0173 
0174 bool Model::resourceHasProperty(const Resource *resource, PropertyPtr property) const
0175 {
0176     return d->resourceHasProperty(resource, property);
0177 }
0178 
0179 bool Model::ModelPrivate::resourceHasProperty(const Resource *resource, PropertyPtr property) const
0180 {
0181     // resource unknown
0182     if (!resources.contains(resource->uri())) {
0183         return false;
0184     }
0185 
0186     const QList<StatementPtr> &stmts = stmtsBySubject[resource->uri()];
0187 
0188     return std::any_of(stmts.cbegin(), stmts.cend(), [&property](const StatementPtr &p) {
0189         return *(p->predicate()) == *property;
0190     });
0191 }
0192 
0193 StatementPtr Model::resourceProperty(const Resource *resource, PropertyPtr property) const
0194 {
0195     return d->resourceProperty(resource, property);
0196 }
0197 
0198 StatementPtr Model::ModelPrivate::resourceProperty(const Resource *resource, PropertyPtr property) const
0199 {
0200     const QList<StatementPtr> &stmts = stmtsBySubject[resource->uri()];
0201     auto it = std::find_if(stmts.cbegin(), stmts.cend(), [&property](const StatementPtr &p) {
0202         return *(p->predicate()) == *property;
0203     });
0204     return it != stmts.cend() ? *it : nullStatement;
0205 }
0206 
0207 QList<StatementPtr> Model::resourceProperties(const Resource *resource, PropertyPtr property) const
0208 {
0209     return d->resourceProperties(resource, property);
0210 }
0211 
0212 QList<StatementPtr> Model::ModelPrivate::resourceProperties(const Resource *resource, PropertyPtr property) const
0213 {
0214     QList<StatementPtr> res;
0215 
0216     const QList<StatementPtr> &stmts = stmtsBySubject[resource->uri()];
0217     for (const auto &p : stmts) {
0218         if (*(p->predicate()) == *property) {
0219             res.append(p);
0220         }
0221     }
0222 
0223     return res;
0224 }
0225 
0226 QList<StatementPtr> Model::statements() const
0227 {
0228     return d->statements.values();
0229 }
0230 
0231 QString Model::debugInfo() const
0232 {
0233     QString info;
0234     for (const StatementPtr &stmtPtr : std::as_const(d->statements)) {
0235         info += QStringLiteral("<%1> <%2> ").arg(stmtPtr->subject()->uri(), stmtPtr->predicate()->uri());
0236 
0237         if (stmtPtr->object()->isLiteral()) {
0238             info += QStringLiteral("\"%1\"\n").arg(stmtPtr->asString());
0239         } else {
0240             info += QStringLiteral("<%1>\n").arg(stmtPtr->asResource()->uri());
0241         }
0242     }
0243 
0244     return info;
0245 }
0246 
0247 QList<ResourcePtr> Model::resourcesWithType(ResourcePtr type) const
0248 {
0249     QList<ResourcePtr> list;
0250 
0251     for (const StatementPtr &stmtPtr : std::as_const(d->statements)) {
0252         if (*(stmtPtr->predicate()) == *(RDFVocab::self()->type()) //
0253             && stmtPtr->object()->isResource() && *(dynamic_cast<Resource *>(stmtPtr->object().data())) == *type) {
0254             list.append(stmtPtr->subject());
0255         }
0256     }
0257 
0258     return list;
0259 }
0260 
0261 NodePtr Model::nodeByID(uint id) const
0262 {
0263     return d->nodeByID(id);
0264 }
0265 
0266 NodePtr Model::ModelPrivate::nodeByID(uint _id) const
0267 {
0268     if (!nodes.contains(_id)) {
0269         return nullLiteral;
0270     } else {
0271         return nodes.value(_id);
0272     }
0273 }
0274 
0275 ResourcePtr Model::resourceByID(uint id) const
0276 {
0277     return d->resourceByID(id);
0278 }
0279 
0280 ResourcePtr Model::ModelPrivate::resourceByID(uint _id) const
0281 {
0282     if (!nodes.contains(_id)) {
0283         return nullResource;
0284     } else {
0285         NodePtr node = nodes.value(_id);
0286         if (node->isResource()) {
0287             return node.staticCast<Resource>();
0288         } else {
0289             return nullResource;
0290         }
0291     }
0292 }
0293 
0294 PropertyPtr Model::propertyByID(uint id) const
0295 {
0296     return d->propertyByID(id);
0297 }
0298 
0299 PropertyPtr Model::ModelPrivate::propertyByID(uint _id) const
0300 {
0301     if (!nodes.contains(_id)) {
0302         return nullProperty;
0303     } else {
0304         NodePtr node = nodes.value(_id);
0305         if (node->isProperty()) {
0306             return node.staticCast<Property>();
0307         } else {
0308             return nullProperty;
0309         }
0310     }
0311 }
0312 
0313 LiteralPtr Model::literalByID(uint id) const
0314 {
0315     return d->literalByID(id);
0316 }
0317 
0318 LiteralPtr Model::ModelPrivate::literalByID(uint _id) const
0319 {
0320     if (!nodes.contains(_id)) {
0321         return nullLiteral;
0322     } else {
0323         NodePtr node = nodes.value(_id);
0324         if (node->isLiteral()) {
0325             return node.staticCast<Literal>();
0326         } else {
0327             return nullLiteral;
0328         }
0329     }
0330 }
0331 
0332 } // namespace RDF
0333 } // namespace Syndication