commit 08c06dc1a8e3f12b48b286d7cf577929d4cce8ea parent f320a207d2e32415c501ffd5a4b2a7462748c7a5 Author: JohnMcPMS <johnmcp@microsoft.com> Date: Fri, 13 Mar 2020 11:31:52 -0700 Properly sort versions in SQLiteIndex (#54) Diffstat:
20 files changed, 477 insertions(+), 30 deletions(-)
diff --git a/src/AppInstallerCLICore/Workflows/ShowFlow.cpp b/src/AppInstallerCLICore/Workflows/ShowFlow.cpp @@ -62,10 +62,11 @@ namespace AppInstaller::Workflow m_reporterRef.ShowMsg("Id: " + app->GetId()); m_reporterRef.ShowMsg("Name: " + app->GetName()); + m_reporterRef.ShowMsg("Versions:"); for (auto& version : app->GetVersions()) { - m_reporterRef.ShowMsg(" Version: " + version.first + ", Channel: " + version.second); + m_reporterRef.ShowMsg(" " + version.ToString()); } } } \ No newline at end of file diff --git a/src/AppInstallerCLICore/Workflows/WorkflowBase.cpp b/src/AppInstallerCLICore/Workflows/WorkflowBase.cpp @@ -101,7 +101,7 @@ namespace AppInstaller::Workflow // Todo: Assume versions are sorted when returned so we'll use the first one as the latest version // Need to call sort if the above is not the case. - std::string msg = app->GetId() + ", " + app->GetName() + ", " + allVersions.at(0).first; + std::string msg = app->GetId() + ", " + app->GetName() + ", " + allVersions.at(0).GetVersion().ToString(); if (match.MatchCriteria.Field != ApplicationMatchField::Id && match.MatchCriteria.Field != ApplicationMatchField::Name) { diff --git a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj @@ -156,6 +156,7 @@ <ClCompile Include="MsixInfo.cpp" /> <ClCompile Include="PreIndexedPackageSource.cpp" /> <ClCompile Include="SQLiteIndexSource.cpp" /> + <ClCompile Include="Versions.cpp" /> <ClCompile Include="WorkFlow.cpp" /> <ClCompile Include="LanguageUtilities.cpp" /> <ClCompile Include="main.cpp"> diff --git a/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters b/src/AppInstallerCLITests/AppInstallerCLITests.vcxproj.filters @@ -77,6 +77,9 @@ <ClCompile Include="HashCommand.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="Versions.cpp"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <None Include="PropertySheet.props" /> diff --git a/src/AppInstallerCLITests/SQLiteIndex.cpp b/src/AppInstallerCLITests/SQLiteIndex.cpp @@ -23,6 +23,7 @@ using namespace AppInstaller::Manifest; using namespace AppInstaller::Repository; using namespace AppInstaller::Repository::Microsoft; using namespace AppInstaller::Repository::SQLite; +using namespace AppInstaller::Utility; SQLiteIndex SimpleTestSetup(const std::string& filePath, Manifest& manifest, std::string& relativePath) { @@ -668,8 +669,56 @@ TEST_CASE("SQLiteIndex_Versions", "[sqliteindex]") auto result = index.GetVersionsById(results[0].first); REQUIRE(result.size() == 1); - REQUIRE(result[0].first == manifest.Version); - REQUIRE(result[0].second == manifest.Channel); + REQUIRE(result[0].GetVersion().ToString() == manifest.Version); + REQUIRE(result[0].GetChannel().ToString() == manifest.Channel); +} + +TEST_CASE("SQLiteIndex_Search_VersionSorting", "[sqliteindex]") +{ + TempFile tempFile{ "repolibtest_tempdb"s, ".db"s }; + INFO("Using temporary file named: " << tempFile.GetPath()); + + std::vector<VersionAndChannel> sortedList = + { + { Version("15.0.0"), Channel("") }, + { Version("14.0.0"), Channel("") }, + { Version("13.2.0-bugfix"), Channel("") }, + { Version("13.2.0"), Channel("") }, + { Version("13.0.0"), Channel("") }, + { Version("16.0.0"), Channel("alpha") }, + { Version("15.8.0"), Channel("alpha") }, + { Version("15.1.0"), Channel("beta") }, + }; + + SQLiteIndex index = SearchTestSetup(tempFile, { + { "Id", "Name", "Moniker", "14.0.0", "", { "foot" }, { "com34" }, "Path1" }, + { "Id", "Name", "Moniker", "16.0.0", "alpha", { "floor" }, { "com3" }, "Path2" }, + { "Id", "Name", "Moniker", "15.0.0", "", {}, { "Command" }, "Path3" }, + { "Id", "Name", "Moniker", "13.2.0", "", {}, { "Command" }, "Path4" }, + { "Id", "Name", "Moniker", "15.1.0", "beta", { "foo" }, { "com3" }, "Path5" }, + { "Id", "Name", "Moniker", "15.8.0", "alpha", { "foo" }, { "com3" }, "Path6" }, + { "Id", "Name", "Moniker", "13.2.0-bugfix", "", { "foo" }, { "com3" }, "Path7" }, + { "Id", "Name", "Moniker", "13.0.0", "", { "foo" }, { "com3" }, "Path8" }, + }); + + SearchRequest request; + request.Filters.emplace_back(ApplicationMatchField::Id, MatchType::Exact, "Id"); + + auto results = index.Search(request); + REQUIRE(results.size() == 1); + + auto result = index.GetVersionsById(results[0].first); + REQUIRE(result.size() == sortedList.size()); + + for (size_t i = 0; i < result.size(); ++i) + { + const VersionAndChannel& sortedVAC = sortedList[i]; + const VersionAndChannel& resultVAC = result[i]; + + INFO(i); + REQUIRE(sortedVAC.GetVersion().ToString() == resultVAC.GetVersion().ToString()); + REQUIRE(sortedVAC.GetChannel().ToString() == resultVAC.GetChannel().ToString()); + } } TEST_CASE("SQLiteIndex_SearchResultsTableSearches", "[sqliteindex][V1_0]") diff --git a/src/AppInstallerCLITests/SQLiteIndexSource.cpp b/src/AppInstallerCLITests/SQLiteIndexSource.cpp @@ -131,8 +131,8 @@ TEST_CASE("SQLiteIndexSource_Versions", "[sqliteindexsource]") auto result = app->GetVersions(); REQUIRE(result.size() == 1); - REQUIRE(result[0].first == manifest.Version); - REQUIRE(result[0].second == manifest.Channel); + REQUIRE(result[0].GetVersion().ToString() == manifest.Version); + REQUIRE(result[0].GetChannel().ToString() == manifest.Channel); } TEST_CASE("SQLiteIndexSource_GetManifest", "[sqliteindexsource]") diff --git a/src/AppInstallerCLITests/Versions.cpp b/src/AppInstallerCLITests/Versions.cpp @@ -0,0 +1,138 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#include "pch.h" +#include "TestCommon.h" +#include <AppInstallerVersions.h> + +using namespace AppInstaller::Utility; + + +TEST_CASE("VersionParse", "[versions]") +{ + Version version("1.2.3.4-alpha"); + const auto& parts = version.GetParts(); + REQUIRE(parts.size() == 4); + for (size_t i = 0; i < parts.size(); ++i) + { + INFO(i); + REQUIRE(parts[i].Integer == static_cast<uint64_t>(i + 1)); + if (i != 3) + { + REQUIRE(parts[i].Other == ""); + } + else + { + REQUIRE(parts[i].Other == "-alpha"); + } + } +} + +TEST_CASE("VersionParsePlusDash", "[versions]") +{ + Version version("1.2.3.4-alpha", ".-"); + const auto& parts = version.GetParts(); + REQUIRE(parts.size() == 5); + for (size_t i = 0; i < 4; ++i) + { + INFO(i); + REQUIRE(parts[i].Integer == static_cast<uint64_t>(i + 1)); + REQUIRE(parts[i].Other == ""); + } + REQUIRE(parts[4].Other == "alpha"); +} + +TEST_CASE("VersionParseCorner", "[versions]") +{ + Version version1(""); + auto parts = version1.GetParts(); + REQUIRE(parts.size() == 0); + + Version version2("."); + parts = version2.GetParts(); + REQUIRE(parts.size() == 0); + + Version version3(".0"); + parts = version3.GetParts(); + REQUIRE(parts.size() == 0); + + Version version4(".1"); + parts = version4.GetParts(); + REQUIRE(parts.size() == 2); + REQUIRE(parts[0].Integer == 0); + REQUIRE(parts[0].Other == ""); + REQUIRE(parts[1].Integer == 1); + REQUIRE(parts[1].Other == ""); + + Version version5("version"); + parts = version5.GetParts(); + REQUIRE(parts.size() == 1); + REQUIRE(parts[0].Integer == 0); + REQUIRE(parts[0].Other == "version"); +} + +void RequireLessThan(std::string_view a, std::string_view b) +{ + Version vA{ std::string(a) }; + Version vB{ std::string(b) }; + + REQUIRE(vA < vB); + REQUIRE(!(vB < vA)); +} + +void RequireEqual(std::string_view a, std::string_view b) +{ + Version vA{ std::string(a) }; + Version vB{ std::string(b) }; + + REQUIRE(!(vA < vB)); + REQUIRE(!(vB < vA)); +} + +TEST_CASE("VersionCompare", "[versions]") +{ + RequireLessThan("1", "2"); + RequireLessThan("1.0.0", "2.0.0"); + RequireLessThan("0.0.1", "0.0.2"); + RequireLessThan("0.0.1-alpha", "0.0.2-alpha"); + RequireLessThan("0.0.1-beta", "0.0.2-alpha"); + RequireLessThan("0.0.1-beta", "0.0.2-alpha"); + RequireLessThan("13.9.8", "14.1"); + + RequireEqual("1.0", "1.0.0"); +} + +TEST_CASE("VersionAndChannelSort", "[versions]") +{ + std::vector<VersionAndChannel> sortedList = + { + { Version("15.0.0"), Channel("") }, + { Version("14.0.0"), Channel("") }, + { Version("13.2.0-bugfix"), Channel("") }, + { Version("13.2.0"), Channel("") }, + { Version("13.0.0"), Channel("") }, + { Version("16.0.0"), Channel("alpha") }, + { Version("15.8.0"), Channel("alpha") }, + { Version("15.1.0"), Channel("beta") }, + }; + + std::vector<size_t> reorderList = { 4, 2, 1, 7, 6, 3, 5, 0 }; + REQUIRE(sortedList.size() == reorderList.size()); + + std::vector<VersionAndChannel> jumbledList; + for (auto i : reorderList) + { + jumbledList.emplace_back(sortedList[i]); + } + + std::sort(jumbledList.begin(), jumbledList.end()); + + for (size_t i = 0; i < jumbledList.size(); ++i) + { + const VersionAndChannel& sortedVAC = sortedList[i]; + const VersionAndChannel& jumbledVAC = jumbledList[i]; + + INFO(i); + REQUIRE(sortedVAC.GetVersion().ToString() == jumbledVAC.GetVersion().ToString()); + REQUIRE(sortedVAC.GetChannel().ToString() == jumbledVAC.GetChannel().ToString()); + } +} diff --git a/src/AppInstallerCLITests/WorkFlow.cpp b/src/AppInstallerCLITests/WorkFlow.cpp @@ -85,10 +85,10 @@ struct TestSource : public ISource return m_manifest.Name; } - std::vector<std::pair<std::string, std::string>> GetVersions() override + std::vector<VersionAndChannel> GetVersions() override { - std::vector<std::pair<std::string, std::string>> result; - result.emplace_back(std::make_pair(m_manifest.Version, m_manifest.Channel)); + std::vector<VersionAndChannel> result; + result.emplace_back(Version(m_manifest.Version), Channel(m_manifest.Channel)); return result; } @@ -420,7 +420,7 @@ TEST_CASE("InstallFlow_SearchAndShowAppVersion", "[ShowFlow]") INFO(showOutput.str()); // Verify App version is printed - REQUIRE(showOutput.str().find("Version: 1.0.0.0") != std::string::npos); + REQUIRE(showOutput.str().find("1.0.0.0") != std::string::npos); // No manifest info is printed REQUIRE(showOutput.str().find("--Installer Download Url: https://ThisIsNotUsed") == std::string::npos); } \ No newline at end of file diff --git a/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj b/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj @@ -187,6 +187,7 @@ <ClInclude Include="Public\AppInstallerTelemetry.h" /> <ClInclude Include="Public\AppInstallerLogging.h" /> <ClInclude Include="Public\AppInstallerArchitecture.h" /> + <ClInclude Include="Public\AppInstallerVersions.h" /> <ClInclude Include="Telemetry\MicrosoftTelemetry.h" /> <ClInclude Include="Telemetry\TraceLogging.h" /> <ClInclude Include="Telemetry\WinEventLogLevels.h" /> @@ -211,6 +212,7 @@ <ClCompile Include="Synchronization.cpp" /> <ClCompile Include="Telemetry\TraceLogging.cpp" /> <ClCompile Include="Architecture.cpp" /> + <ClCompile Include="Versions.cpp" /> </ItemGroup> <ItemGroup> <None Include="packages.config" /> diff --git a/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj.filters b/src/AppInstallerCommonCore/AppInstallerCommonCore.vcxproj.filters @@ -90,6 +90,9 @@ <ClInclude Include="Public\AppInstallerProgress.h"> <Filter>Public</Filter> </ClInclude> + <ClInclude Include="Public\AppInstallerVersions.h"> + <Filter>Public</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ClCompile Include="pch.cpp"> @@ -143,6 +146,9 @@ <ClCompile Include="Deployment.cpp"> <Filter>Source Files</Filter> </ClCompile> + <ClCompile Include="Versions.cpp"> + <Filter>Source Files</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <None Include="PropertySheet.props" /> diff --git a/src/AppInstallerCommonCore/Public/AppInstallerVersions.h b/src/AppInstallerCommonCore/Public/AppInstallerVersions.h @@ -0,0 +1,98 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#pragma once +#include <string> +#include <string_view> +#include <vector> + +namespace AppInstaller::Utility +{ + using namespace std::string_view_literals; + + // Creates a comparable version object from a string. + // Versions are parsed by: + // 1. Splitting the string based on the given splitChars (or DefaultSplitChars) + // 2. Parsing a leading, positive integer from each split part + // 3. Saving any remaining, non-digits as a supplemental value + // + // Versions are compared by: + // for each part in each version + // if both sides have no more parts, return equal + // else if one side has no more parts, it is less + // else if integers not equal, return comparison of integers + // else if string parts not equal, return comparison of strings + struct Version + { + // The default characters to split a version string on. + constexpr static std::string_view DefaultSplitChars = "."sv; + + Version(const std::string& version, std::string_view splitChars = DefaultSplitChars) : + Version(std::string(version), splitChars) {} + Version(std::string&& version, std::string_view splitChars = DefaultSplitChars); + + // Gets the full version string used to construct the Version. + const std::string& ToString() const { return m_version; } + + bool operator<(const Version& other) const; + + // An individual version part in between split characters. + struct Part + { + Part(const std::string& part); + + bool operator<(const Part& other) const; + + uint64_t Integer = 0; + std::string Other; + }; + + // Gets the part breakdown for a given version; used for tests. + const std::vector<Part>& GetParts() const { return m_parts; } + + private: + std::string m_version; + std::vector<Part> m_parts; + }; + + // A channel string; existing solely to give a type. + // + // Compared lexographically. + struct Channel + { + Channel(const std::string& channel) : m_channel(channel) {} + Channel(std::string&& channel) : m_channel(std::move(channel)) {} + + const std::string& ToString() const { return m_channel; } + + bool operator<(const Channel& other) const; + + private: + std::string m_channel; + }; + + // Contains a version and channel. + // These are compared by: + // if channel not equal, return compare channel + // else return !compare version + // + // The implication of this is that the default less sort will be: + // 2.0, "" + // 1.0, "" + // 3.0, "alpha" + // 2.0, "alpha" + struct VersionAndChannel + { + VersionAndChannel(Version&& version, Channel&& channel); + + const Version& GetVersion() const { return m_version; } + const Channel& GetChannel() const { return m_channel; } + + std::string ToString() const; + + bool operator<(const VersionAndChannel& other) const; + + private: + Version m_version; + Channel m_channel; + }; +} diff --git a/src/AppInstallerCommonCore/Versions.cpp b/src/AppInstallerCommonCore/Versions.cpp @@ -0,0 +1,138 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#include "pch.h" +#include "Public/AppInstallerVersions.h" + +namespace AppInstaller::Utility +{ + Version::Version(std::string&& version, std::string_view splitChars) : + m_version(std::move(version)) + { + size_t pos = 0; + + while (pos < m_version.length()) + { + size_t newPos = m_version.find_first_of(splitChars, pos); + + size_t length = (newPos == std::string::npos ? m_version.length() : newPos) - pos; + m_parts.emplace_back(m_version.substr(pos, length)); + + pos += length + 1; + } + + // Remove trailing empty versions (0 or empty) + while (!m_parts.empty()) + { + const Part& part = m_parts.back(); + if (part.Integer == 0 && part.Other.empty()) + { + m_parts.pop_back(); + } + else + { + break; + } + } + } + + bool Version::operator<(const Version& other) const + { + for (size_t i = 0; i < m_parts.size(); ++i) + { + if (i >= other.m_parts.size()) + { + // All parts equal to this point + break; + } + + const Part& partA = m_parts[i]; + const Part& partB = other.m_parts[i]; + + if (partA < partB) + { + return true; + } + else if (partB < partA) + { + return false; + } + // else parts are equal, so continue to next part + } + + // All parts tested were equal, so this is only less if there are more parts in other. + return m_parts.size() < other.m_parts.size(); + } + + Version::Part::Part(const std::string& part) + { + size_t end = 0; + try + { + Integer = std::stoull(part, &end); + } + CATCH_LOG(); + if (end != part.length()) + { + Other = part.substr(end); + } + } + + bool Version::Part::operator<(const Part& other) const + { + if (Integer < other.Integer) + { + return true; + } + else if (Integer > other.Integer) + { + return false; + } + else if (Other < other.Other) + { + return true; + } + + // else Other >= other.Other + return false; + } + + bool Channel::operator<(const Channel& other) const + { + return m_channel < other.m_channel; + } + + VersionAndChannel::VersionAndChannel(Version&& version, Channel&& channel) : + m_version(std::move(version)), m_channel(std::move(channel)) {} + + std::string VersionAndChannel::ToString() const + { + std::string result; + result = m_version.ToString(); + if (!m_channel.ToString().empty()) + { + result += ", "; + result += m_channel.ToString(); + } + return result; + } + + bool VersionAndChannel::operator<(const VersionAndChannel& other) const + { + if (m_channel < other.m_channel) + { + return true; + } + else if (other.m_channel < m_channel) + { + return false; + } + // We intentionally invert the order for version here. + else if (other.m_version < m_version) + { + return true; + } + + // else m_verson >= other.m_version + return false; + } +} diff --git a/src/AppInstallerRepositoryCore/Microsoft/SQLiteIndex.cpp b/src/AppInstallerRepositoryCore/Microsoft/SQLiteIndex.cpp @@ -219,7 +219,7 @@ namespace AppInstaller::Repository::Microsoft return m_interface->GetPathStringByKey(m_dbconn, id, version, channel); } - std::vector<std::pair<std::string, std::string>> SQLiteIndex::GetVersionsById(IdType id) + std::vector<Utility::VersionAndChannel> SQLiteIndex::GetVersionsById(IdType id) { return m_interface->GetVersionsById(m_dbconn, id); } diff --git a/src/AppInstallerRepositoryCore/Microsoft/SQLiteIndex.h b/src/AppInstallerRepositoryCore/Microsoft/SQLiteIndex.h @@ -6,6 +6,7 @@ #include "Microsoft/Schema/Version.h" #include "Public/AppInstallerRepositorySearch.h" #include <AppInstallerLanguageUtilities.h> +#include <AppInstallerVersions.h> #include <chrono> #include <filesystem> @@ -93,7 +94,7 @@ namespace AppInstaller::Repository::Microsoft std::optional<std::string> GetPathStringByKey(IdType id, std::string_view version, std::string_view channel); // Gets all versions and channels for the given id. - std::vector<std::pair<std::string, std::string>> GetVersionsById(IdType id); + std::vector<Utility::VersionAndChannel> GetVersionsById(IdType id); private: // Constructor used to open an existing index. diff --git a/src/AppInstallerRepositoryCore/Microsoft/SQLiteIndexSource.cpp b/src/AppInstallerRepositoryCore/Microsoft/SQLiteIndexSource.cpp @@ -58,7 +58,7 @@ namespace AppInstaller::Repository::Microsoft } } - std::vector<std::pair<std::string, std::string>> GetVersions() override + std::vector<Utility::VersionAndChannel> GetVersions() override { return GetSource()->GetIndex().GetVersionsById(m_id); } diff --git a/src/AppInstallerRepositoryCore/Microsoft/Schema/1_0/Interface.cpp b/src/AppInstallerRepositoryCore/Microsoft/Schema/1_0/Interface.cpp @@ -72,26 +72,34 @@ namespace AppInstaller::Repository::Microsoft::Schema::V1_0 if (version.empty()) { - std::vector<std::string> versions; + std::vector<std::string> versionStrings; if (channelIdOpt) { - versions = ManifestTable::GetAllValuesByIds<VersionTable, IdTable, ChannelTable>(connection, { id, channelIdOpt.value() }); + versionStrings = ManifestTable::GetAllValuesByIds<VersionTable, IdTable, ChannelTable>(connection, { id, channelIdOpt.value() }); } else { - versions = ManifestTable::GetAllValuesByIds<VersionTable, IdTable>(connection, { id }); + versionStrings = ManifestTable::GetAllValuesByIds<VersionTable, IdTable>(connection, { id }); } - if (versions.empty()) + if (versionStrings.empty()) { AICLI_LOG(Repo, Info, << "Did not find any Versions { " << id << ", " << channel << " }"); return {}; } - // TODO: Implement version sort, for now assume latest == lastest - const std::string& latestVersion = versions[versions.size() - 1]; + // Convert the strings to Versions and sort them + std::vector<Utility::Version> versions; + for (std::string& v : versionStrings) + { + versions.emplace_back(std::move(v)); + } + + std::sort(versions.begin(), versions.end()); + // Get the first version in the list and its rowid + const std::string& latestVersion = versions[0].ToString(); versionIdOpt = VersionTable::SelectIdByValue(connection, latestVersion); } else @@ -450,19 +458,19 @@ namespace AppInstaller::Repository::Microsoft::Schema::V1_0 return PathPartTable::GetPathById(connection, pathPartId); } - std::vector<std::pair<std::string, std::string>> Interface::GetVersionsById(SQLite::Connection& connection, SQLite::rowid_t id) + std::vector<Utility::VersionAndChannel> Interface::GetVersionsById(SQLite::Connection& connection, SQLite::rowid_t id) { auto versionsAndChannels = ManifestTable::GetAllValuesById<IdTable, VersionTable, ChannelTable>(connection, id); - // TODO: Implement version sort, for now assume latest == lastest - std::reverse(versionsAndChannels.begin(), versionsAndChannels.end()); - - std::vector<std::pair<std::string, std::string>> result; + std::vector<Utility::VersionAndChannel> result; result.reserve(versionsAndChannels.size()); for (auto&& vac : versionsAndChannels) { - result.emplace_back(std::make_pair(std::move(std::get<0>(vac)), std::move(std::get<1>(vac)))); + result.emplace_back(Utility::Version{ std::move(std::get<0>(vac)) }, Utility::Channel{ std::move(std::get<1>(vac)) }); } + + std::sort(result.begin(), result.end()); + return result; } } diff --git a/src/AppInstallerRepositoryCore/Microsoft/Schema/1_0/Interface.h b/src/AppInstallerRepositoryCore/Microsoft/Schema/1_0/Interface.h @@ -20,6 +20,6 @@ namespace AppInstaller::Repository::Microsoft::Schema::V1_0 std::optional<std::string> GetIdStringById(SQLite::Connection& connection, SQLite::rowid_t id) override; std::optional<std::string> GetNameStringById(SQLite::Connection& connection, SQLite::rowid_t id) override; std::optional<std::string> GetPathStringByKey(SQLite::Connection& connection, SQLite::rowid_t id, std::string_view version, std::string_view channel) override; - std::vector<std::pair<std::string, std::string>> GetVersionsById(SQLite::Connection& connection, SQLite::rowid_t id) override; + std::vector<Utility::VersionAndChannel> GetVersionsById(SQLite::Connection& connection, SQLite::rowid_t id) override; }; } diff --git a/src/AppInstallerRepositoryCore/Microsoft/Schema/ISQLiteIndex.h b/src/AppInstallerRepositoryCore/Microsoft/Schema/ISQLiteIndex.h @@ -5,6 +5,7 @@ #include "Manifest/Manifest.h" #include "Microsoft/Schema/Version.h" #include "Public/AppInstallerRepositorySearch.h" +#include <AppInstallerVersions.h> #include <filesystem> @@ -55,7 +56,7 @@ namespace AppInstaller::Repository::Microsoft::Schema virtual std::optional<std::string> GetPathStringByKey(SQLite::Connection& connection, SQLite::rowid_t id, std::string_view version, std::string_view channel) = 0; // Gets all versions and channels for the given id. - virtual std::vector<std::pair<std::string, std::string>> GetVersionsById(SQLite::Connection& connection, SQLite::rowid_t id) = 0; + virtual std::vector<Utility::VersionAndChannel> GetVersionsById(SQLite::Connection& connection, SQLite::rowid_t id) = 0; }; diff --git a/src/AppInstallerRepositoryCore/Public/AppInstallerRepositorySearch.h b/src/AppInstallerRepositoryCore/Public/AppInstallerRepositorySearch.h @@ -2,6 +2,7 @@ // Licensed under the MIT License. #pragma once #include <Manifest/Manifest.h> +#include <AppInstallerVersions.h> #include <memory> #include <optional> @@ -82,10 +83,9 @@ namespace AppInstaller::Repository virtual Manifest::Manifest GetManifest(std::string_view version, std::string_view channel) = 0; // Gets all versions of this application. - // The pair is <version, channel>. - // The versions will be returned in sorted, desceding order. + // The versions will be returned in sorted, descending order. // Ex. { 4, 3, 2, 1 } - virtual std::vector<std::pair<std::string, std::string>> GetVersions() = 0; + virtual std::vector<Utility::VersionAndChannel> GetVersions() = 0; }; // A single result from the search. diff --git a/src/AppInstallerRepositoryCore/pch.h b/src/AppInstallerRepositoryCore/pch.h @@ -15,6 +15,7 @@ #include <AppInstallerSHA256.h> #include <AppInstallerStrings.h> #include <AppInstallerSynchronization.h> +#include <AppInstallerVersions.h> #include <yaml-cpp/yaml.h> #include <wil/result_macros.h>