File indexing completed on 2024-05-19 05:42:07
0001 // ct_lvtldr_lakosiannode.cpp -*-C++-*- 0002 0003 /* 0004 // Copyright 2023 Codethink Ltd <codethink@codethink.co.uk> 0005 // SPDX-License-Identifier: Apache-2.0 0006 // 0007 // Licensed under the Apache License, Version 2.0 (the "License"); 0008 // you may not use this file except in compliance with the License. 0009 // You may obtain a copy of the License at 0010 // 0011 // http://www.apache.org/licenses/LICENSE-2.0 0012 // 0013 // Unless required by applicable law or agreed to in writing, software 0014 // distributed under the License is distributed on an "AS IS" BASIS, 0015 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 0016 // See the License for the specific language governing permissions and 0017 // limitations under the License. 0018 */ 0019 0020 #include <ct_lvtldr_lakosiannode.h> 0021 0022 #include <ct_lvtldr_nodestorage.h> 0023 0024 #include <QObject> 0025 #include <QString> 0026 #include <QStringList> 0027 0028 #include <algorithm> 0029 #include <cassert> 0030 #include <filesystem> 0031 #include <unordered_map> 0032 #include <vector> 0033 0034 using namespace Codethink::lvtshr; 0035 0036 namespace Codethink::lvtldr { 0037 0038 std::vector<std::string> NamingUtils::buildQualifiedNamePrefixParts(const std::string& qname, 0039 const std::string& separator) 0040 { 0041 auto qtVector = QString::fromStdString(qname).split(QString::fromStdString(separator)); 0042 auto stdVector = std::vector<std::string>{}; 0043 std::transform(qtVector.begin(), qtVector.end(), std::back_inserter(stdVector), [](auto&& qtString) { 0044 return qtString.toStdString(); 0045 }); 0046 stdVector.pop_back(); 0047 return stdVector; 0048 } 0049 0050 std::string NamingUtils::buildQualifiedName(const std::vector<std::string>& parts, 0051 const std::string& name, 0052 const std::string& separator) 0053 { 0054 auto qname = std::string{}; 0055 for (auto const& namePart : parts) { 0056 qname += namePart + separator; 0057 } 0058 qname += name; 0059 return qname; 0060 } 0061 0062 // ========================== 0063 // class LakosianNode 0064 // ========================== 0065 0066 LakosianNode::LakosianNode(NodeStorage& store, std::optional<std::reference_wrapper<DatabaseHandler>> dbHandler): 0067 d(std::make_unique<Private>(store, dbHandler)) 0068 { 0069 } 0070 0071 LakosianNode::~LakosianNode() noexcept = default; 0072 0073 bool LakosianNode::isPackageGroup() 0074 { 0075 // default implementation 0076 return false; 0077 } 0078 0079 std::string LakosianNode::notes() const 0080 { 0081 if (d->dbHandler->get().hasNotes(uid())) { 0082 return d->dbHandler->get().getNotesFromId(uid()); 0083 } 0084 return ""; 0085 } 0086 0087 LakosianNode *LakosianNode::parent() 0088 { 0089 loadParent(); 0090 assert(d->parentLoaded); 0091 return d->parent; 0092 } 0093 0094 std::string LakosianNode::name() const 0095 { 0096 return d->name; 0097 } 0098 0099 void LakosianNode::setNotes(const std::string& notes) 0100 { 0101 if (!d->dbHandler->get().hasNotes(uid())) { 0102 d->dbHandler->get().addNotes(uid(), notes); 0103 } else { 0104 d->dbHandler->get().setNotes(uid(), notes); 0105 } 0106 0107 Q_EMIT onNotesChanged(notes); 0108 } 0109 0110 void LakosianNode::setName(const std::string& newName) 0111 { 0112 d->name = newName; 0113 Q_EMIT onNameChanged(this); 0114 } 0115 0116 const std::vector<LakosianNode *>& LakosianNode::children() 0117 { 0118 const auto currChildren = d->children.size(); 0119 auto childrenWasLoaded = d->childrenLoaded; 0120 loadChildren(); 0121 0122 assert(d->childrenLoaded); 0123 if (currChildren != d->children.size() || !childrenWasLoaded) { 0124 Q_EMIT onChildCountChanged(d->children.size()); 0125 } 0126 0127 return d->children; 0128 } 0129 0130 const std::vector<LakosianEdge>& LakosianNode::providers() 0131 { 0132 loadProviders(); 0133 assert(d->providersLoaded); 0134 return d->providers; 0135 } 0136 0137 void LakosianNode::invalidateProviders() 0138 { 0139 // TODO [#455]: It is possible to update providers, instead of fetching all over again from database. 0140 d->providersLoaded = false; 0141 d->providers.clear(); 0142 } 0143 0144 void LakosianNode::invalidateChildren() 0145 { 0146 d->childrenLoaded = false; 0147 d->children.clear(); 0148 } 0149 0150 void LakosianNode::invalidateParent() 0151 { 0152 d->parentLoaded = false; 0153 d->parent = nullptr; 0154 } 0155 0156 const std::vector<LakosianEdge>& LakosianNode::clients() 0157 { 0158 loadClients(); 0159 assert(d->clientsLoaded); 0160 return d->clients; 0161 } 0162 0163 void LakosianNode::invalidateClients() 0164 { 0165 // TODO [#455]: It is possible to update clients, instead of fetching all over again from database. 0166 d->clientsLoaded = false; 0167 d->clients.clear(); 0168 } 0169 0170 bool LakosianNode::hasProvider(LakosianNode *other) 0171 { 0172 const auto& deps = providers(); 0173 return std::find_if(std::cbegin(deps), 0174 std::cend(deps), 0175 [&](const auto& dep) { 0176 return dep.other() == other; 0177 }) 0178 != std::cend(deps); 0179 } 0180 0181 bool operator==(const LakosianNode& lhs, const LakosianNode& rhs) 0182 { 0183 return lhs.type() == rhs.type() && lhs.id() == rhs.id(); 0184 } 0185 0186 std::vector<LakosianNode *> LakosianNode::parentHierarchy() 0187 { 0188 // parent-hierarchy of the physical node. 0189 auto *tmp = this; 0190 std::vector<LakosianNode *> hierarchy; 0191 while (tmp) { 0192 hierarchy.push_back(tmp); 0193 tmp = tmp->parent(); 0194 } 0195 std::reverse(std::begin(hierarchy), std::end(hierarchy)); 0196 return hierarchy; 0197 } 0198 0199 LakosianNode *LakosianNode::topLevelParent() 0200 { 0201 LakosianNode *parentPtr = this; 0202 while (parentPtr) { 0203 if (!parentPtr->parent()) { 0204 break; 0205 } 0206 parentPtr = parentPtr->parent(); 0207 } 0208 0209 return parentPtr; 0210 } 0211 0212 } // namespace Codethink::lvtldr