commit 841496f9cd710ec09eb9a046a7565545652af759
parent 1ac30f8509d01671aa4f69f559d3fbcd1da2f142
Author: JohnMcPMS <johnmcp@microsoft.com>
Date: Wed, 11 Mar 2020 12:45:45 -0700
Implement running all given filters (#50)
Diffstat:
7 files changed, 275 insertions(+), 46 deletions(-)
diff --git a/src/AppInstallerCLITests/SQLiteIndex.cpp b/src/AppInstallerCLITests/SQLiteIndex.cpp
@@ -755,7 +755,7 @@ TEST_CASE("SQLiteIndex_Search_ExactBeforeSubstring", "[sqliteindex]")
REQUIRE(index.GetIdStringById(results[1].first) == "Id2");
}
-TEST_CASE("SQLiteIndex_Search_Filter", "[sqliteindex]")
+TEST_CASE("SQLiteIndex_Search_SingleFilter", "[sqliteindex]")
{
TempFile tempFile{ "repolibtest_tempdb"s, ".db"s };
INFO("Using temporary file named: " << tempFile.GetPath());
@@ -800,3 +800,55 @@ TEST_CASE("SQLiteIndex_Search_Multimatch", "[sqliteindex]")
auto results = index.Search(request);
REQUIRE(results.size() == 3);
}
+
+TEST_CASE("SQLiteIndex_Search_QueryAndFilter", "[sqliteindex]")
+{
+ TempFile tempFile{ "repolibtest_tempdb"s, ".db"s };
+ INFO("Using temporary file named: " << tempFile.GetPath());
+
+ SQLiteIndex index = SearchTestSetup(tempFile, {
+ { "Nope", "Name", "Moniker", "Version", "Channel", { "Tag" }, { "Command" }, "Path1" },
+ { "Id2", "Na", "Moniker", "Version", "Channel", { "Tag" }, { "Command" }, "Path2" },
+ { "Id3", "No", "Moniker", "Version", "Channel", { "Tag" }, { "Command" }, "Path3" },
+ });
+
+ SearchRequest request;
+ request.Query = RequestMatch(MatchType::Substring, "Id");
+ request.Filters.emplace_back(ApplicationMatchField::Name, MatchType::Substring, "Na");
+
+ auto results = index.Search(request);
+ REQUIRE(results.size() == 1);
+
+ auto result = index.GetIdStringById(results[0].first);
+ REQUIRE(result.has_value());
+ REQUIRE(result.value() == "Id2");
+}
+
+TEST_CASE("SQLiteIndex_Search_QueryAndMultipleFilters", "[sqliteindex]")
+{
+ TempFile tempFile{ "repolibtest_tempdb"s, ".db"s };
+ INFO("Using temporary file named: " << tempFile.GetPath());
+
+ SQLiteIndex index = SearchTestSetup(tempFile, {
+ { "Id1", "Name", "Moniker", "Version", "Channel", { "foot" }, { "com34" }, "Path1" },
+ { "Id1", "Name1", "Moniker", "Version1", "Channel", { "floor" }, { "com3" }, "Path2" },
+ { "Id2", "Name", "Moniker", "Version", "", {}, { "Command" }, "Path3" },
+ { "Id2", "Name", "Moniker", "Version", "Channel", {}, { "Command" }, "Path4" },
+ { "Id3", "Tagit", "Moniker", "Version1", "", { "foo" }, { "com3" }, "Path5" },
+ { "Id3", "Tagit", "Moniker", "Version2", "", { "foo" }, { "com3" }, "Path6" },
+ { "Id3", "Tagit", "new", "Version3", "", { "foo" }, { "com3" }, "Path7" },
+ });
+
+ SearchRequest request;
+ request.Query = RequestMatch(MatchType::Substring, "tag");
+ request.Filters.emplace_back(ApplicationMatchField::Command, MatchType::Exact, "com3");
+ request.Filters.emplace_back(ApplicationMatchField::Tag, MatchType::Substring, "foo");
+ request.Filters.emplace_back(ApplicationMatchField::Moniker, MatchType::Substring, "new");
+
+ auto results = index.Search(request);
+ REQUIRE(results.size() == 1);
+
+ auto result = index.GetIdStringById(results[0].first);
+ REQUIRE(result.has_value());
+ REQUIRE(result.value() == "Id3");
+}
diff --git a/src/AppInstallerRepositoryCore/Microsoft/Schema/1_0/Interface.cpp b/src/AppInstallerRepositoryCore/Microsoft/Schema/1_0/Interface.cpp
@@ -141,9 +141,9 @@ namespace AppInstaller::Repository::Microsoft::Schema::V1_0
case MatchType::Wildcard:
return { MatchType::Wildcard };
case MatchType::Fuzzy:
- return { MatchType::Exact, MatchType::Substring, MatchType::Fuzzy };
+ return { MatchType::Exact, MatchType::Fuzzy };
case MatchType::FuzzySubstring:
- return { MatchType::Exact, MatchType::Substring, MatchType::Fuzzy, MatchType::FuzzySubstring };
+ return { MatchType::Exact, MatchType::Fuzzy, MatchType::Substring, MatchType::FuzzySubstring };
default:
THROW_HR(E_UNEXPECTED);
}
@@ -379,7 +379,7 @@ namespace AppInstaller::Repository::Microsoft::Schema::V1_0
{
THROW_HR_IF(E_UNEXPECTED, request.Filters.empty());
- // Perform search for just the field matching this filter
+ // Perform search for just the field matching the first filter
const ApplicationMatchFilter& filter = request.Filters[0];
for (MatchType match : GetMatchTypeOrder(filter.Type))
diff --git a/src/AppInstallerRepositoryCore/Microsoft/Schema/1_0/SearchResultsTable.cpp b/src/AppInstallerRepositoryCore/Microsoft/Schema/1_0/SearchResultsTable.cpp
@@ -27,10 +27,38 @@ namespace AppInstaller::Repository::Microsoft::Schema::V1_0
constexpr std::string_view s_SearchResultsTable_SortValue = "sort"sv;
constexpr std::string_view s_SearchResultsTable_Filter = "filter"sv;
+ constexpr std::string_view s_SearchResultsTable_Index_Suffix = "_i_m"sv;
+
constexpr std::string_view s_SearchResultsTable_SubSelect_TableAlias = "valueTable"sv;
constexpr std::string_view s_SearchResultsTable_SubSelect_ManifestAlias = "m"sv;
constexpr std::string_view s_SearchResultsTable_SubSelect_ValueAlias = "v"sv;
+ bool MatchUsesLike(MatchType match)
+ {
+ return (match != MatchType::Exact);
+ }
+
+ int BuildSearchStatement(SQLite::Builder::StatementBuilder& builder, ApplicationMatchField field, MatchType match)
+ {
+ bool useLike = MatchUsesLike(match);
+
+ switch (field)
+ {
+ case ApplicationMatchField::Id:
+ return ManifestTable::BuildSearchStatement<IdTable>(builder, s_SearchResultsTable_SubSelect_ManifestAlias, s_SearchResultsTable_SubSelect_ValueAlias, useLike);
+ case ApplicationMatchField::Name:
+ return ManifestTable::BuildSearchStatement<NameTable>(builder, s_SearchResultsTable_SubSelect_ManifestAlias, s_SearchResultsTable_SubSelect_ValueAlias, useLike);
+ case ApplicationMatchField::Moniker:
+ return ManifestTable::BuildSearchStatement<MonikerTable>(builder, s_SearchResultsTable_SubSelect_ManifestAlias, s_SearchResultsTable_SubSelect_ValueAlias, useLike);
+ case ApplicationMatchField::Tag:
+ return ManifestTable::BuildSearchStatement<TagsTable>(builder, s_SearchResultsTable_SubSelect_ManifestAlias, s_SearchResultsTable_SubSelect_ValueAlias, useLike);
+ case ApplicationMatchField::Command:
+ return ManifestTable::BuildSearchStatement<CommandsTable>(builder, s_SearchResultsTable_SubSelect_ManifestAlias, s_SearchResultsTable_SubSelect_ValueAlias, useLike);
+ default:
+ THROW_HR(E_UNEXPECTED);
+ }
+ }
+
void ExecuteStatementForMatchType(SQLite::Statement& statement, MatchType match, int bindIndex, bool escapeValueForLike, std::string_view value)
{
// TODO: Implement these more complex match types
@@ -65,21 +93,35 @@ namespace AppInstaller::Repository::Microsoft::Schema::V1_0
{
using namespace SQLite::Builder;
- StatementBuilder builder;
- builder.CreateTable(GetQualifiedName()).BeginColumns();
+ {
+ StatementBuilder builder;
+ builder.CreateTable(GetQualifiedName()).BeginColumns();
- builder.Column(ColumnBuilder(s_SearchResultsTable_Manifest, Type::RowId).NotNull());
- builder.Column(ColumnBuilder(s_SearchResultsTable_MatchField, Type::Int).NotNull());
- builder.Column(ColumnBuilder(s_SearchResultsTable_MatchType, Type::Int).NotNull());
- builder.Column(ColumnBuilder(s_SearchResultsTable_MatchValue, Type::Text).NotNull());
- builder.Column(ColumnBuilder(s_SearchResultsTable_SortValue, Type::Int).NotNull());
- builder.Column(ColumnBuilder(s_SearchResultsTable_Filter, Type::Bool).NotNull());
+ builder.Column(ColumnBuilder(s_SearchResultsTable_Manifest, Type::RowId).NotNull());
+ builder.Column(ColumnBuilder(s_SearchResultsTable_MatchField, Type::Int).NotNull());
+ builder.Column(ColumnBuilder(s_SearchResultsTable_MatchType, Type::Int).NotNull());
+ builder.Column(ColumnBuilder(s_SearchResultsTable_MatchValue, Type::Text).NotNull());
+ builder.Column(ColumnBuilder(s_SearchResultsTable_SortValue, Type::Int).NotNull());
+ builder.Column(ColumnBuilder(s_SearchResultsTable_Filter, Type::Bool).NotNull());
- builder.EndColumns();
+ builder.EndColumns();
- builder.Execute(m_connection);
+ builder.Execute(m_connection);
+ }
InitDropStatement(m_connection);
+
+ {
+ SQLite::Builder::QualifiedTable index = GetQualifiedName();
+ std::string indexName(index.Table);
+ indexName += s_SearchResultsTable_Index_Suffix;
+ index.Table = indexName;
+
+ StatementBuilder builder;
+ builder.CreateIndex(indexName).On(GetQualifiedName().Table).Columns(s_SearchResultsTable_Manifest);
+
+ builder.Execute(m_connection);
+ }
}
void SearchResultsTable::SearchOnField(ApplicationMatchField field, MatchType match, std::string_view value)
@@ -104,56 +146,78 @@ namespace AppInstaller::Repository::Microsoft::Schema::V1_0
Value(false).
From().BeginParenthetical();
- bool useLike = (match != MatchType::Exact);
- int bindIndex = 0;
-
- switch (field)
- {
- case ApplicationMatchField::Id:
- bindIndex = ManifestTable::BuildSearchStatement<IdTable>(builder, s_SearchResultsTable_SubSelect_ManifestAlias, s_SearchResultsTable_SubSelect_ValueAlias, useLike);
- break;
- case ApplicationMatchField::Name:
- bindIndex = ManifestTable::BuildSearchStatement<NameTable>(builder, s_SearchResultsTable_SubSelect_ManifestAlias, s_SearchResultsTable_SubSelect_ValueAlias, useLike);
- break;
- case ApplicationMatchField::Moniker:
- bindIndex = ManifestTable::BuildSearchStatement<MonikerTable>(builder, s_SearchResultsTable_SubSelect_ManifestAlias, s_SearchResultsTable_SubSelect_ValueAlias, useLike);
- break;
- case ApplicationMatchField::Tag:
- bindIndex = ManifestTable::BuildSearchStatement<TagsTable>(builder, s_SearchResultsTable_SubSelect_ManifestAlias, s_SearchResultsTable_SubSelect_ValueAlias, useLike);
- break;
- case ApplicationMatchField::Command:
- bindIndex = ManifestTable::BuildSearchStatement<CommandsTable>(builder, s_SearchResultsTable_SubSelect_ManifestAlias, s_SearchResultsTable_SubSelect_ValueAlias, useLike);
- break;
- default:
- THROW_HR(E_UNEXPECTED);
- }
+ // Add the field specific portion
+ int bindIndex = BuildSearchStatement(builder, field, match);
builder.EndParenthetical().As(s_SearchResultsTable_SubSelect_TableAlias);
SQLite::Statement statement = builder.Prepare(m_connection);
- ExecuteStatementForMatchType(statement, match, bindIndex, useLike, value);
+ ExecuteStatementForMatchType(statement, match, bindIndex, MatchUsesLike(match), value);
}
void SearchResultsTable::RemoveDuplicateManifestRows()
{
+ using namespace SQLite::Builder;
+ // Create a delete statement to leave only one row with a given manifest.
+ // This will arbitrarily choose one of the rows if multiple have the same lowest sort order.
+ // The goal is a statement like this:
+ // DELETE from <temp> where rowid not in (
+ // SELECT rowid from (
+ // SELECT rowid, min(sort) from <temp> group by manifest
+ // )
+ // )
+ StatementBuilder builder;
+ builder.DeleteFrom(GetQualifiedName()).Where(SQLite::RowIDName).Not().In().BeginParenthetical().
+ Select(SQLite::RowIDName).From().BeginParenthetical().
+ Select().Column(SQLite::RowIDName).Column(Aggregate::Min, s_SearchResultsTable_SortValue).From(GetQualifiedName()).GroupBy(s_SearchResultsTable_Manifest).
+ EndParenthetical().
+ EndParenthetical();
+
+ builder.Execute(m_connection);
}
void SearchResultsTable::PrepareToFilter()
{
+ // Reset all filter values to unselected
+ SQLite::Builder::StatementBuilder builder;
+ builder.Update(GetQualifiedName()).Set().Column(s_SearchResultsTable_Filter).Equals(false);
+ builder.Execute(m_connection);
}
void SearchResultsTable::FilterOnField(ApplicationMatchField field, MatchType match, std::string_view value)
{
- UNREFERENCED_PARAMETER(field);
- UNREFERENCED_PARAMETER(match);
- UNREFERENCED_PARAMETER(value);
+ using namespace SQLite::Builder;
+
+ // Create an update statement to mark rows that are found by the search.
+ // This will arbitrarily choose one of the rows if multiple have the same lowest sort order.
+ // The goal is a statement like this:
+ // UPDATE <temp> set filter = 1 where manifest in (
+ // SELECT m from (
+ // SELECT manifest.rowid as m, manifest.id as v from manifest join ids on manifest.id = ids.rowid where ids.id = <value>
+ // )
+ // )
+ StatementBuilder builder;
+ builder.Update(GetQualifiedName()).Set().Column(s_SearchResultsTable_Filter).Equals(true).Where(s_SearchResultsTable_Manifest).In().BeginParenthetical().
+ Select(s_SearchResultsTable_SubSelect_ManifestAlias).From().BeginParenthetical();
+
+ // Add the field specific portion
+ int bindIndex = BuildSearchStatement(builder, field, match);
+
+ builder.EndParenthetical().EndParenthetical();
+
+ SQLite::Statement statement = builder.Prepare(m_connection);
+ ExecuteStatementForMatchType(statement, match, bindIndex, MatchUsesLike(match), value);
}
void SearchResultsTable::CompleteFilter()
{
+ // Delete all unselected values
+ SQLite::Builder::StatementBuilder builder;
+ builder.DeleteFrom(GetQualifiedName()).Where(s_SearchResultsTable_Filter).Equals(false);
+ builder.Execute(m_connection);
}
std::vector<std::pair<SQLite::rowid_t, ApplicationMatchFilter>> SearchResultsTable::GetSearchResults(size_t limit)
diff --git a/src/AppInstallerRepositoryCore/SQLiteStatementBuilder.cpp b/src/AppInstallerRepositoryCore/SQLiteStatementBuilder.cpp
@@ -8,7 +8,21 @@ namespace AppInstaller::Repository::SQLite::Builder
{
std::ostream& operator<<(std::ostream& out, const QualifiedColumn& column)
{
- out << '[' << column.Table << "].[" << column.Column << ']';
+ if (!column.Table.empty())
+ {
+ out << '[' << column.Table << "].";
+ }
+ out << '[' << column.Column << ']';
+ return out;
+ }
+
+ std::ostream& operator<<(std::ostream& out, const QualifiedTable& table)
+ {
+ if (!table.Schema.empty())
+ {
+ out << '[' << table.Schema << "].";
+ }
+ out << '[' << table.Table << ']';
return out;
}
@@ -94,6 +108,11 @@ namespace AppInstaller::Repository::SQLite::Builder
out << op << " [" << table << ']';
}
+ void OutputOperationAndTable(std::ostream& out, std::string_view op, QualifiedTable table)
+ {
+ out << op << table;
+ }
+
void OutputOperationAndTable(std::ostream& out, std::string_view op, std::initializer_list<std::string_view> table)
{
out << op << " [";
@@ -248,6 +267,12 @@ namespace AppInstaller::Repository::SQLite::Builder
return *this;
}
+ StatementBuilder& StatementBuilder::From(QualifiedTable table)
+ {
+ OutputOperationAndTable(m_stream, " FROM", table);
+ return *this;
+ }
+
StatementBuilder& StatementBuilder::From(std::initializer_list<std::string_view> table)
{
OutputOperationAndTable(m_stream, " FROM", table);
@@ -293,6 +318,18 @@ namespace AppInstaller::Repository::SQLite::Builder
THROW_HR(E_NOTIMPL);
}
+ StatementBuilder& StatementBuilder::Not()
+ {
+ m_stream << " NOT";
+ return *this;
+ }
+
+ StatementBuilder& StatementBuilder::In()
+ {
+ m_stream << " IN";
+ return *this;
+ }
+
StatementBuilder& StatementBuilder::IsNull()
{
m_stream << " IS NULL";
@@ -317,6 +354,12 @@ namespace AppInstaller::Repository::SQLite::Builder
return *this;
}
+ StatementBuilder& StatementBuilder::Join(QualifiedTable table)
+ {
+ OutputOperationAndTable(m_stream, " JOIN", table);
+ return *this;
+ }
+
StatementBuilder& StatementBuilder::Join(std::initializer_list<std::string_view> table)
{
OutputOperationAndTable(m_stream, " JOIN", table);
@@ -365,6 +408,12 @@ namespace AppInstaller::Repository::SQLite::Builder
return *this;
}
+ StatementBuilder& StatementBuilder::InsertInto(QualifiedTable table)
+ {
+ OutputOperationAndTable(m_stream, "INSERT INTO", table);
+ return *this;
+ }
+
StatementBuilder& StatementBuilder::InsertInto(std::initializer_list<std::string_view> table)
{
OutputOperationAndTable(m_stream, "INSERT INTO", table);
@@ -495,6 +544,12 @@ namespace AppInstaller::Repository::SQLite::Builder
return *this;
}
+ StatementBuilder& StatementBuilder::CreateTable(QualifiedTable table)
+ {
+ OutputOperationAndTable(m_stream, "CREATE TABLE", table);
+ return *this;
+ }
+
StatementBuilder& StatementBuilder::CreateTable(std::initializer_list<std::string_view> table)
{
OutputOperationAndTable(m_stream, "CREATE TABLE", table);
@@ -507,6 +562,12 @@ namespace AppInstaller::Repository::SQLite::Builder
return *this;
}
+ StatementBuilder& StatementBuilder::DropTable(QualifiedTable table)
+ {
+ OutputOperationAndTable(m_stream, "DROP TABLE", table);
+ return *this;
+ }
+
StatementBuilder& StatementBuilder::DropTable(std::initializer_list<std::string_view> table)
{
OutputOperationAndTable(m_stream, "DROP TABLE", table);
@@ -519,6 +580,12 @@ namespace AppInstaller::Repository::SQLite::Builder
return *this;
}
+ StatementBuilder& StatementBuilder::CreateIndex(QualifiedTable table)
+ {
+ OutputOperationAndTable(m_stream, "CREATE INDEX", table);
+ return *this;
+ }
+
StatementBuilder& StatementBuilder::CreateIndex(std::initializer_list<std::string_view> table)
{
OutputOperationAndTable(m_stream, "CREATE INDEX", table);
@@ -531,6 +598,12 @@ namespace AppInstaller::Repository::SQLite::Builder
return *this;
}
+ StatementBuilder& StatementBuilder::DropIndex(QualifiedTable table)
+ {
+ OutputOperationAndTable(m_stream, "DROP INDEX", table);
+ return *this;
+ }
+
StatementBuilder& StatementBuilder::DropIndex(std::initializer_list<std::string_view> table)
{
OutputOperationAndTable(m_stream, "DROP INDEX", table);
@@ -555,6 +628,12 @@ namespace AppInstaller::Repository::SQLite::Builder
return *this;
}
+ StatementBuilder& StatementBuilder::DeleteFrom(QualifiedTable table)
+ {
+ OutputOperationAndTable(m_stream, "DELETE FROM", table);
+ return *this;
+ }
+
StatementBuilder& StatementBuilder::DeleteFrom(std::initializer_list<std::string_view> table)
{
OutputOperationAndTable(m_stream, "DELETE FROM", table);
@@ -567,6 +646,12 @@ namespace AppInstaller::Repository::SQLite::Builder
return *this;
}
+ StatementBuilder& StatementBuilder::Update(QualifiedTable table)
+ {
+ OutputOperationAndTable(m_stream, "UPDATE", table);
+ return *this;
+ }
+
StatementBuilder& StatementBuilder::Update(std::initializer_list<std::string_view> table)
{
OutputOperationAndTable(m_stream, "UPDATE", table);
diff --git a/src/AppInstallerRepositoryCore/SQLiteStatementBuilder.h b/src/AppInstallerRepositoryCore/SQLiteStatementBuilder.h
@@ -61,6 +61,16 @@ namespace AppInstaller::Repository::SQLite::Builder
// Pass this value to indicate that the number of rows is to be selected.
__declspec_selectany_ details::rowcount_t RowCount;
+ // A qualified table reference.
+ struct QualifiedTable
+ {
+ std::string_view Schema;
+ std::string_view Table;
+
+ explicit QualifiedTable(std::string_view table) : Table(table) {}
+ explicit QualifiedTable(std::string_view schema, std::string_view table) : Schema(schema), Table(table) {}
+ };
+
// A qualified column reference.
struct QualifiedColumn
{
@@ -162,6 +172,7 @@ namespace AppInstaller::Repository::SQLite::Builder
// The initializer_list form enables the table name to be constructed from multiple parts.
StatementBuilder& From();
StatementBuilder& From(std::string_view table);
+ StatementBuilder& From(QualifiedTable table);
StatementBuilder& From(std::initializer_list<std::string_view> table);
// Begin a filter clause on the given column.
@@ -194,6 +205,9 @@ namespace AppInstaller::Repository::SQLite::Builder
StatementBuilder& Like(details::unbound_t);
StatementBuilder& Escape(std::string_view escapeChar);
+ StatementBuilder& Not();
+ StatementBuilder& In();
+
StatementBuilder& IsNull();
// Operators for combining filter clauses.
@@ -203,6 +217,7 @@ namespace AppInstaller::Repository::SQLite::Builder
// Begin a join clause.
// The initializer_list form enables the table name to be constructed from multiple parts.
StatementBuilder& Join(std::string_view table);
+ StatementBuilder& Join(QualifiedTable table);
StatementBuilder& Join(std::initializer_list<std::string_view> table);
// Set the join constraint.
@@ -222,6 +237,7 @@ namespace AppInstaller::Repository::SQLite::Builder
// Begin an insert statement for the given table.
// The initializer_list form enables the table name to be constructed from multiple parts.
StatementBuilder& InsertInto(std::string_view table);
+ StatementBuilder& InsertInto(QualifiedTable table);
StatementBuilder& InsertInto(std::initializer_list<std::string_view> table);
// Set the columns for a statement (typically insert).
@@ -263,21 +279,25 @@ namespace AppInstaller::Repository::SQLite::Builder
// Begin a table creation statement.
// The initializer_list form enables the table name to be constructed from multiple parts.
StatementBuilder& CreateTable(std::string_view table);
+ StatementBuilder& CreateTable(QualifiedTable table);
StatementBuilder& CreateTable(std::initializer_list<std::string_view> table);
// Begin an table deletion statement.
// The initializer_list form enables the table name to be constructed from multiple parts.
StatementBuilder& DropTable(std::string_view table);
+ StatementBuilder& DropTable(QualifiedTable table);
StatementBuilder& DropTable(std::initializer_list<std::string_view> table);
// Begin an index creation statement.
// The initializer_list form enables the table name to be constructed from multiple parts.
StatementBuilder& CreateIndex(std::string_view table);
+ StatementBuilder& CreateIndex(QualifiedTable table);
StatementBuilder& CreateIndex(std::initializer_list<std::string_view> table);
// Begin an index deletion statement.
// The initializer_list form enables the table name to be constructed from multiple parts.
StatementBuilder& DropIndex(std::string_view table);
+ StatementBuilder& DropIndex(QualifiedTable table);
StatementBuilder& DropIndex(std::initializer_list<std::string_view> table);
// Set index target table.
@@ -287,11 +307,13 @@ namespace AppInstaller::Repository::SQLite::Builder
// Begin a delete statement.
// The initializer_list form enables the table name to be constructed from multiple parts.
StatementBuilder& DeleteFrom(std::string_view table);
+ StatementBuilder& DeleteFrom(QualifiedTable table);
StatementBuilder& DeleteFrom(std::initializer_list<std::string_view> table);
// Begin an update statement.
// The initializer_list form enables the table name to be constructed from multiple parts.
StatementBuilder& Update(std::string_view table);
+ StatementBuilder& Update(QualifiedTable table);
StatementBuilder& Update(std::initializer_list<std::string_view> table);
// Output the set portion of an update statement.
diff --git a/src/AppInstallerRepositoryCore/SQLiteTempTable.cpp b/src/AppInstallerRepositoryCore/SQLiteTempTable.cpp
@@ -3,11 +3,12 @@
#pragma once
#include "pch.h"
#include "SQLiteTempTable.h"
-#include "SQLiteStatementBuilder.h"
namespace AppInstaller::Repository::SQLite
{
+ using namespace std::string_view_literals;
+
TempTable::TempTable()
{
GUID tempName;
@@ -16,8 +17,7 @@ namespace AppInstaller::Repository::SQLite
wchar_t guidAsString[MAX_PATH];
THROW_HR_IF(E_UNEXPECTED, StringFromGUID2(tempName, guidAsString, MAX_PATH) == 0);
- m_name = "temp].[";
- m_name += Utility::ConvertToUTF8(guidAsString);
+ m_name = Utility::ConvertToUTF8(guidAsString);
}
TempTable::~TempTable()
@@ -28,6 +28,11 @@ namespace AppInstaller::Repository::SQLite
}
}
+ Builder::QualifiedTable TempTable::GetQualifiedName() const
+ {
+ return Builder::QualifiedTable("temp"sv, m_name);
+ }
+
void TempTable::InitDropStatement(Connection& connection)
{
Builder::StatementBuilder builder;
diff --git a/src/AppInstallerRepositoryCore/SQLiteTempTable.h b/src/AppInstallerRepositoryCore/SQLiteTempTable.h
@@ -2,6 +2,7 @@
// Licensed under the MIT License.
#pragma once
#include "SQLiteWrapper.h"
+#include "SQLiteStatementBuilder.h"
namespace AppInstaller::Repository::SQLite
@@ -21,7 +22,7 @@ namespace AppInstaller::Repository::SQLite
protected:
// Gets the qualified name of the temp table.
- const std::string& GetQualifiedName() const { return m_name; }
+ Builder::QualifiedTable GetQualifiedName() const;
// Prepares the drop table statement for use in destructor.
// It needs to be run by the derived class after the table is actually created.