SQLiteIndex.h (10327B)
1 // Copyright (c) Microsoft Corporation. 2 // Licensed under the MIT License. 3 #pragma once 4 #include <winget/SQLiteWrapper.h> 5 #include "Microsoft/Schema/ISQLiteIndex.h" 6 #include <winget/SQLiteVersion.h> 7 #include <winget/SQLiteStorageBase.h> 8 #include "ISource.h" 9 #include <AppInstallerLanguageUtilities.h> 10 #include <AppInstallerVersions.h> 11 #include <winget/Manifest.h> 12 #include <winget/NameNormalization.h> 13 #include <winget/ManagedFile.h> 14 15 #include <filesystem> 16 #include <limits> 17 #include <memory> 18 #include <optional> 19 #include <string> 20 #include <utility> 21 #include <vector> 22 23 namespace AppInstaller::Repository::Microsoft 24 { 25 // Holds the connection to the database, as well as the appropriate functionality to interface with it. 26 struct SQLiteIndex : SQLite::SQLiteStorageBase 27 { 28 // An id that refers to a specific application. 29 using IdType = SQLite::rowid_t; 30 31 // The return type of Search 32 using SearchResult = Schema::ISQLiteIndex::SearchResult; 33 34 // The return type of GetMetadataByManifestId 35 using MetadataResult = Schema::ISQLiteIndex::MetadataResult; 36 37 // Options for creating a new index. 38 using CreateOptions = Schema::ISQLiteIndex::CreateOptions; 39 40 // The type of version keys. 41 using VersionKey = Schema::ISQLiteIndex::VersionKey; 42 43 SQLiteIndex(const SQLiteIndex&) = delete; 44 SQLiteIndex& operator=(const SQLiteIndex&) = delete; 45 46 SQLiteIndex(SQLiteIndex&&) = default; 47 SQLiteIndex& operator=(SQLiteIndex&&) = default; 48 49 // Creates a new index database of the given version. 50 static SQLiteIndex CreateNew(const std::string& filePath, SQLite::Version version = SQLite::Version::Latest(), CreateOptions options = CreateOptions::None); 51 52 // Opens an existing SQLiteIndex database. 53 static SQLiteIndex Open(const std::string& filePath, OpenDisposition disposition, Utility::ManagedFile&& indexFile = {}); 54 55 // Creates a copy of the given index. 56 static SQLiteIndex CopyFrom(const std::string& filePath, SQLiteIndex& source); 57 58 #ifndef AICLI_DISABLE_TEST_HOOKS 59 // Changes the version of the interface being used to operate on the database. 60 // Should only be used for testing. 61 void ForceVersion(const SQLite::Version& version); 62 63 // Gets the latest version of the index schema (the actual numbers, not just the latest sentinel values). 64 static SQLite::Version GetLatestVersion(); 65 66 // Gets the context data for testing. 67 const Schema::SQLiteIndexContextData& GetContextData() const; 68 #endif 69 70 // Adds the manifest at the repository relative path to the index. 71 // If the function succeeds, the manifest has been added. 72 // Returns the manifest id. 73 IdType AddManifest(const std::filesystem::path& manifestPath, const std::filesystem::path& relativePath); 74 75 // Adds the manifest at the repository relative path to the index. 76 // If the function succeeds, the manifest has been added. 77 // Returns the manifest id. 78 IdType AddManifest(const Manifest::Manifest& manifest, const std::filesystem::path& relativePath); 79 80 // Adds the manifest to the index. 81 // If the function succeeds, the manifest has been added. 82 // Returns the manifest id. 83 IdType AddManifest(const Manifest::Manifest& manifest); 84 85 // Updates the manifest with matching { Id, Version, Channel } in the index. 86 // The return value indicates whether the index was modified by the function. 87 bool UpdateManifest(const std::filesystem::path& manifestPath, const std::filesystem::path& relativePath); 88 89 // Updates the manifest with matching { Id, Version, Channel } in the index. 90 // The return value indicates whether the index was modified by the function. 91 bool UpdateManifest(const Manifest::Manifest& manifest, const std::filesystem::path& relativePath); 92 93 // Updates the manifest with matching { Id, Version, Channel } in the index. 94 // The return value indicates whether the index was modified by the function. 95 bool UpdateManifest(const Manifest::Manifest& manifest); 96 97 // Adds or updates the manifest with matching { Id, Version, Channel } in the index. 98 // The return value indicates whether the manifest was added (true) or updated (false). 99 bool AddOrUpdateManifest(const std::filesystem::path& manifestPath, const std::filesystem::path& relativePath); 100 101 // Updates the manifest with matching { Id, Version, Channel } in the index. 102 // The return value indicates whether the manifest was added (true) or updated (false). 103 bool AddOrUpdateManifest(const Manifest::Manifest& manifest, const std::filesystem::path& relativePath); 104 105 // Updates the manifest with matching { Id, Version, Channel } in the index. 106 // The return value indicates whether the manifest was added (true) or updated (false). 107 bool AddOrUpdateManifest(const Manifest::Manifest& manifest); 108 109 // Removes the manifest with matching { Id, Version, Channel } from the index. 110 void RemoveManifest(const std::filesystem::path& manifestPath, const std::filesystem::path& relativePath); 111 112 // Removes the manifest with matching { Id, Version, Channel } from the index. 113 void RemoveManifest(const Manifest::Manifest& manifest, const std::filesystem::path& relativePath); 114 115 // Removes the manifest with matching { Id, Version, Channel } from the index. 116 void RemoveManifest(const Manifest::Manifest& manifest); 117 118 // Removes the manifest with the given id. 119 void RemoveManifestById(IdType manifestId); 120 121 // Removes data that is no longer needed for an index that is to be published. 122 void PrepareForPackaging(); 123 124 // Checks the consistency of the index to ensure that every referenced row exists. 125 // Returns true if index is consistent; false if it is not. 126 bool CheckConsistency(bool log = false) const; 127 128 // Performs a search based on the given criteria. 129 SearchResult Search(const SearchRequest& request) const; 130 131 // Gets the string for the given property and primary id, if present. 132 std::optional<std::string> GetPropertyByPrimaryId(IdType primaryId, PackageVersionProperty property) const; 133 134 // Gets the string values for the given property and primary id, if present. 135 std::vector<std::string> GetMultiPropertyByPrimaryId(IdType primaryId, PackageVersionMultiProperty property) const; 136 137 // Gets the manifest id for the given { id, version, channel }, if present. 138 // If version is empty, gets the value for the 'latest' version. 139 std::optional<IdType> GetManifestIdByKey(IdType id, std::string_view version, std::string_view channel) const; 140 141 // Gets the manifest id for the given manifest, if present. 142 std::optional<IdType> GetManifestIdByManifest(const Manifest::Manifest& manifest) const; 143 144 // Gets all versions and channels for the given id. 145 std::vector<VersionKey> GetVersionKeysById(IdType id) const; 146 147 // Gets the string for the given metadata and manifest id, if present. 148 MetadataResult GetMetadataByManifestId(SQLite::rowid_t manifestId) const; 149 150 // Sets the string for the given metadata and manifest id. 151 void SetMetadataByManifestId(IdType manifestId, PackageVersionMetadata metadata, std::string_view value); 152 153 // Normalizes a name using the internal rules used by the index. 154 // Largely a utility function; should not be used to do work on behalf of the index by the caller. 155 Utility::NormalizedName NormalizeName(std::string_view name, std::string_view publisher) const; 156 157 // Get all the dependencies for a specific manifest. 158 std::set<std::pair<SQLite::rowid_t, Utility::NormalizedString>> GetDependenciesByManifestRowId(SQLite::rowid_t manifestRowId) const; 159 std::vector<std::pair<SQLite::rowid_t, Utility::NormalizedString>> GetDependentsById(AppInstaller::Manifest::string_t packageId) const; 160 161 // Migrates the index to the target version. 162 // Returns false to indicate that the requested migration is not supported. 163 bool MigrateTo(SQLite::Version version); 164 165 // The property values that can be set. 166 enum class Property 167 { 168 PackageUpdateTrackingBaseTime, 169 IntermediateFileOutputPath, 170 }; 171 172 // Sets the given property. 173 // Some properties will persist into the database. 174 void SetProperty(Property property, const std::string& value); 175 176 private: 177 // Constructor used to create a new index. 178 SQLiteIndex(const std::string& target, const SQLite::Version& version); 179 180 // Constructor used to open an existing index. 181 SQLiteIndex(const std::string& target, SQLiteStorageBase::OpenDisposition disposition, Utility::ManagedFile&& indexFile); 182 183 // Constructor used to copy the given index. 184 SQLiteIndex(const std::string& target, SQLiteIndex& source); 185 186 // Sets the database file path in the context data if appropriate. 187 void SetDatabaseFilePath(const std::string& target); 188 189 // Internal functions to normalize on the relativePath being present. 190 IdType AddManifestInternal(const Manifest::Manifest& manifest, const std::optional<std::filesystem::path>& relativePath); 191 IdType AddManifestInternalHoldingLock(const Manifest::Manifest& manifest, const std::optional<std::filesystem::path>& relativePath); 192 bool UpdateManifestInternal(const Manifest::Manifest& manifest, const std::optional<std::filesystem::path>& relativePath); 193 bool UpdateManifestInternalHoldingLock(const Manifest::Manifest& manifest, const std::optional<std::filesystem::path>& relativePath); 194 bool AddOrUpdateManifestInternal(const Manifest::Manifest& manifest, const std::optional<std::filesystem::path>& relativePath); 195 196 std::unique_ptr<Schema::ISQLiteIndex> m_interface; 197 Schema::SQLiteIndexContextData m_contextData; 198 }; 199 }