File indexing completed on 2024-05-19 05:42:07

0001 // ct_lvtldr_lakosiannode.h                                           -*-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 #ifndef INCLUDED_CT_LVTLDR_LAKOSIANNODE
0021 #define INCLUDED_CT_LVTLDR_LAKOSIANNODE
0022 
0023 //@PURPOSE: Types *internal to lvtldr* used to cache loaded graphs in memory
0024 //
0025 //@CLASSES:
0026 //  lvtldr::NodeStorage: Append-only store of LakosianNodes with fast lookup
0027 //  lvtldr::LakosianEdge: Models a relation between LakosianNodes
0028 //  lvtldr::LakosianNode: Representation of one node in the graph we loaded from
0029 //                        the database
0030 //  lvtldr::TypeNode: Implementation of LakosianNode for UDTs
0031 //  lvtldr::ComponentNode: Implementation of LakosianNode for components
0032 //  lvtldr::PackageNode: Implementation of LakosianNode for packages
0033 
0034 #include <lvtldr_export.h>
0035 
0036 #include <ct_lvtldr_lakosianedge.h>
0037 
0038 #include <ct_lvtldr_databasehandler.h>
0039 #include <ct_lvtshr_graphenums.h>
0040 #include <ct_lvtshr_uniqueid.h>
0041 
0042 #include <QObject>
0043 
0044 #include <functional>
0045 #include <memory>
0046 #include <string>
0047 #include <vector>
0048 
0049 #include <result/result.hpp>
0050 
0051 namespace Codethink::lvtldr {
0052 
0053 // FORWARD DECLARATIONS
0054 class LakosianNode;
0055 
0056 // TODO: Remove NodeStorage from this class. there should be no reason that a Node needs to know *how* it's stored.
0057 class NodeStorage;
0058 
0059 struct LVTLDR_EXPORT AddChildError {
0060     std::string what;
0061 };
0062 
0063 struct LVTLDR_EXPORT NamingUtils {
0064     static std::vector<std::string> buildQualifiedNamePrefixParts(const std::string& qname,
0065                                                                   const std::string& separator);
0066     static std::string
0067     buildQualifiedName(const std::vector<std::string>& parts, const std::string& name, const std::string& separator);
0068 };
0069 
0070 // ==========================
0071 // class LakosianNode
0072 // ==========================
0073 
0074 class LVTLDR_EXPORT LakosianNode : public QObject {
0075     Q_OBJECT
0076     // A node in a physical graph. This could be a package group, package,
0077     // component or type.
0078     // Should not be used outside of lvtldr.
0079 
0080   protected:
0081     // TYPES
0082     struct Private {
0083         NodeStorage& store;
0084         std::optional<std::reference_wrapper<DatabaseHandler>> dbHandler = std::nullopt;
0085 
0086         std::string name;
0087 
0088         bool parentLoaded = false;
0089         bool childrenLoaded = false;
0090         bool providersLoaded = false;
0091         bool clientsLoaded = false;
0092         bool fieldsLoaded = false;
0093 
0094         LakosianNode *parent = nullptr;
0095         std::vector<LakosianNode *> children;
0096         std::vector<LakosianNode *> innerPackages;
0097         std::vector<LakosianEdge> providers;
0098         std::vector<LakosianEdge> clients;
0099         std::vector<std::string> fieldNames;
0100 
0101         explicit Private(NodeStorage& store, std::optional<std::reference_wrapper<DatabaseHandler>> dbHandler):
0102             store(store), dbHandler(dbHandler)
0103         {
0104         }
0105     };
0106 
0107     // DATA
0108     std::unique_ptr<Private> d; // NOLINT
0109 
0110     // MODIFIERS
0111     virtual void loadParent() = 0;
0112     // Load the parent (if any) of this node
0113 
0114     virtual void loadChildren() = 0;
0115     // Load the children (if any) of this node
0116 
0117     virtual void loadProviders() = 0;
0118     // Load the forward dependencies (if any) of this node
0119 
0120     virtual void loadClients() = 0;
0121     // Load the reverse dependencies (if any) of this node
0122 
0123   public:
0124     enum class IsLakosianResult {
0125         IsLakosian,
0126         ComponentHasNoPackage,
0127         ComponentDoesntStartWithParentName,
0128         PackageParentIsNotGroup,
0129         PackagePrefixDiffersFromGroup,
0130         PackageNameInvalidNumberOfChars,
0131         PackageGroupNameInvalidNumberOfChars
0132     };
0133 
0134     // CREATORS
0135     explicit LakosianNode(NodeStorage& store, std::optional<std::reference_wrapper<DatabaseHandler>> dbHandler);
0136     // Stores the database session as a reference, so the SessionPtr
0137     // must outlive this LakosianNode
0138 
0139     virtual ~LakosianNode() noexcept;
0140 
0141     // ACCESSORS
0142     [[nodiscard]] virtual lvtshr::DiagramType type() const = 0;
0143     [[nodiscard]] virtual bool isPackageGroup();
0144     // Unfortunately lvtshr::DiagramType doesn't distinguish between packages
0145     // and package groups
0146 
0147     // For adding to IGraphLoader
0148     [[nodiscard]] virtual std::string qualifiedName() const = 0;
0149     [[nodiscard]] virtual std::string parentName() = 0;
0150     [[nodiscard]] virtual long long id() const = 0;
0151 
0152     [[nodiscard]] virtual lvtshr::UniqueId uid() const = 0;
0153 
0154     [[nodiscard]] virtual IsLakosianResult isLakosian() = 0;
0155 
0156     virtual cpp::result<void, AddChildError> addChild(LakosianNode *child) = 0;
0157     // Add a child to this node NodeStorage.
0158     // Useful when creating a Node manually.
0159 
0160     [[nodiscard]] virtual std::string name() const;
0161     virtual void setName(std::string const& newName);
0162 
0163     // these aren't const because they are lazy-loaded
0164 
0165     LakosianNode *parent();
0166     // Returns the parent of this LakosianNode,
0167     // or nullptr if there is no parent.
0168 
0169     LakosianNode *topLevelParent();
0170     // Returns the parent of this LakosianNode,
0171     // or itself, if it's the toplevel entity.
0172 
0173     std::vector<LakosianNode *> parentHierarchy();
0174     // first element is the topmost parent, last element is this node.
0175 
0176     const std::vector<LakosianNode *>& children();
0177 
0178     const std::vector<LakosianEdge>& providers();
0179     const std::vector<LakosianEdge>& clients();
0180 
0181     const std::vector<std::string>& fields();
0182 
0183     std::string notes() const;
0184     void setNotes(const std::string& setNotes);
0185 
0186     void invalidateProviders();
0187     void invalidateClients();
0188     virtual void invalidateChildren();
0189     void invalidateParent();
0190 
0191     bool hasProvider(LakosianNode *other);
0192 
0193     // signals
0194     Q_SIGNAL void onNameChanged(LakosianNode *);
0195     Q_SIGNAL void onChildCountChanged(size_t);
0196     Q_SIGNAL void onNotesChanged(std::string);
0197 };
0198 
0199 LVTLDR_EXPORT bool operator==(const LakosianNode& lhs, const LakosianNode& rhs);
0200 
0201 template<typename T>
0202 struct LakosianNodeType {
0203 };
0204 
0205 } // namespace Codethink::lvtldr
0206 
0207 #endif // INCLUDED_CT_LVTLDR_LAKOSIANNODE