ManifestTable.h (12515B)
1 // Copyright (c) Microsoft Corporation. 2 // Licensed under the MIT License. 3 #pragma once 4 #include <winget/SQLiteWrapper.h> 5 #include <winget/SQLiteStatementBuilder.h> 6 #include "Microsoft/Schema/1_0/VirtualTableBase.h" 7 #include <initializer_list> 8 #include <optional> 9 #include <string_view> 10 #include <utility> 11 #include <vector> 12 13 14 namespace AppInstaller::Repository::Microsoft::Schema::V1_0 15 { 16 namespace details 17 { 18 template<typename Table> 19 std::string_view GetManifestTableColumnName() 20 { 21 if constexpr (std::is_base_of<VirtualTableBase, Table>()) 22 { 23 return Table::ManifestColumnName(); 24 } 25 else 26 { 27 return Table::ValueName(); 28 } 29 } 30 31 // Selects a manifest by the given value id. 32 std::optional<SQLite::rowid_t> ManifestTableSelectByValueIds( 33 const SQLite::Connection& connection, 34 std::initializer_list<std::string_view> values, 35 std::initializer_list<SQLite::rowid_t> ids); 36 37 // Gets the requested ids for the manifest with the given rowid. 38 SQLite::Statement ManifestTableGetIdsById_Statement( 39 const SQLite::Connection& connection, 40 SQLite::rowid_t id, 41 std::initializer_list<std::string_view> values, 42 bool stepAndVerify = true); 43 44 // Gets the requested values for the manifest with the given rowid. 45 SQLite::Statement ManifestTableGetValuesById_Statement( 46 const SQLite::Connection& connection, 47 SQLite::rowid_t id, 48 std::initializer_list<SQLite::Builder::QualifiedColumn> columns, 49 std::initializer_list<std::string_view> manifestColumnNames, 50 bool stepAndVerify = true); 51 52 // Gets all values for rows that match the given ids. 53 SQLite::Statement ManifestTableGetAllValuesByIds_Statement( 54 const SQLite::Connection& connection, 55 std::initializer_list<SQLite::Builder::QualifiedColumn> valueColumns, 56 std::initializer_list<SQLite::Builder::QualifiedColumn> joinColumns, 57 std::initializer_list<std::string_view> idColumns, 58 std::initializer_list<SQLite::rowid_t> ids); 59 60 // Gets all values for rows that match the given ids. 61 std::vector<std::pair<SQLite::rowid_t, std::string>> ManifestTableGetAllValuesByIds( 62 const SQLite::Connection& connection, 63 std::initializer_list<SQLite::Builder::QualifiedColumn> valueColumns, 64 std::initializer_list<SQLite::Builder::QualifiedColumn> joinColumns, 65 std::initializer_list<std::string_view> idColumns, 66 std::initializer_list<SQLite::rowid_t> ids); 67 68 // Builds the search select statement base on the given values. 69 std::vector<int> ManifestTableBuildSearchStatement( 70 SQLite::Builder::StatementBuilder& builder, 71 std::initializer_list<SQLite::Builder::QualifiedColumn> columns, 72 std::initializer_list<bool> isOneToOnes, 73 std::string_view manifestAlias, 74 std::string_view valueAlias, 75 bool useLike); 76 77 // Prepares a statement to update the value of a single column for the manifest with the given rowid. 78 // The first bind value will be the value to set. 79 // The second bind value will be the manifest rowid to modify. 80 SQLite::Statement ManifestTableUpdateValueIdById_Statement(SQLite::Connection& connection, std::string_view valueName); 81 82 // Checks the consistency of the index to ensure that every referenced row exists. 83 // Returns true if index is consistent; false if it is not. 84 bool ManifestTableCheckConsistency(const SQLite::Connection& connection, const SQLite::Builder::QualifiedColumn& target, std::string_view manifestColumnName, bool log); 85 } 86 87 // Info on the manifest columns. 88 struct ManifestColumnInfo 89 { 90 std::string_view Name; 91 bool PrimaryKey; 92 bool Unique; 93 }; 94 95 // Information on a column being added via ALTER TABLE 96 struct AddedColumnInfo 97 { 98 std::string_view Name; 99 SQLite::Builder::Type Type; 100 }; 101 102 // A value that is 1:1 with the manifest. 103 struct ManifestOneToOneValue 104 { 105 std::string_view Name; 106 SQLite::rowid_t Value; 107 }; 108 109 // A table that represents a single manifest 110 struct ManifestTable 111 { 112 // Get the table name. 113 static std::string_view TableName(); 114 115 // Creates the table with named indices. 116 static void Create(SQLite::Connection& connection, std::initializer_list<ManifestColumnInfo> values); 117 118 // Alters the table, adding the columns provided. 119 static void AddColumn(SQLite::Connection& connection, AddedColumnInfo value); 120 121 // Creates the table with standard primary keys. 122 static void Create_deprecated(SQLite::Connection& connection, std::initializer_list<ManifestColumnInfo> values); 123 124 // Drops the table. 125 static void Drop(SQLite::Connection& connection); 126 127 // Insert the given values into the table. 128 static SQLite::rowid_t Insert(SQLite::Connection& connection, std::initializer_list<ManifestOneToOneValue> values); 129 130 // Gets a value indicating whether the manifest with rowid id exists. 131 static bool ExistsById(const SQLite::Connection& connection, SQLite::rowid_t id); 132 133 // Select the first rowid of the manifest with the given value. 134 template <typename... Tables> 135 static std::optional<SQLite::rowid_t> SelectByValueIds(const SQLite::Connection& connection, std::initializer_list<SQLite::rowid_t> ids) 136 { 137 static_assert(sizeof...(Tables) >= 1); 138 return details::ManifestTableSelectByValueIds(connection, { Tables::ValueName()... }, ids); 139 } 140 141 // Gets the ids requested for the manifest with the given rowid. 142 template <typename... Tables> 143 static auto GetIdsById(const SQLite::Connection& connection, SQLite::rowid_t id) 144 { 145 return details::ManifestTableGetIdsById_Statement(connection, id, { details::GetManifestTableColumnName<Tables>()...}).GetRow<typename Tables::id_t...>(); 146 } 147 148 // Gets the id requested for the manifest with the given rowid, if it exists. 149 template <typename Table> 150 static std::optional<typename Table::id_t> GetIdById(const SQLite::Connection& connection, SQLite::rowid_t id) 151 { 152 auto statement = details::ManifestTableGetIdsById_Statement(connection, id, { details::GetManifestTableColumnName<Table>() }, false); 153 if (statement.Step()) { return statement.GetColumn<typename Table::id_t>(0); } 154 else { return std::nullopt; } 155 } 156 157 // Gets the values requested for the manifest with the given rowid. 158 template <typename... Tables> 159 static auto GetValuesById(const SQLite::Connection& connection, SQLite::rowid_t id) 160 { 161 return details::ManifestTableGetValuesById_Statement(connection, id, { SQLite::Builder::QualifiedColumn{ Tables::TableName(), Tables::ValueName() }... }, { details::GetManifestTableColumnName<Tables>()... }).GetRow<typename Tables::value_t...>(); 162 } 163 164 // Gets the value requested for the manifest with the given rowid, if it exists. 165 template <typename Table> 166 static std::optional<typename Table::value_t> GetValueById(const SQLite::Connection& connection, SQLite::rowid_t id) 167 { 168 auto statement = details::ManifestTableGetValuesById_Statement(connection, id, { SQLite::Builder::QualifiedColumn{ Table::TableName(), Table::ValueName() } }, { details::GetManifestTableColumnName<Table>() }, false); 169 if (statement.Step()) { return statement.GetColumn<typename Table::value_t>(0); } 170 else { return std::nullopt; } 171 } 172 173 // Gets the row ids and values for rows that match the given ids. 174 template <typename ValueTable, typename... IdTables> 175 static std::vector<std::pair<SQLite::rowid_t, typename ValueTable::value_t>> GetAllValuesByIds(const SQLite::Connection& connection, std::initializer_list<SQLite::rowid_t> ids) 176 { 177 return details::ManifestTableGetAllValuesByIds(connection, 178 { SQLite::Builder::QualifiedColumn{ ValueTable::TableName(), SQLite::RowIDName }, SQLite::Builder::QualifiedColumn{ ValueTable::TableName(), ValueTable::ValueName() } }, 179 { SQLite::Builder::QualifiedColumn{ ValueTable::TableName(), ValueTable::ValueName() } }, 180 { IdTables::ValueName()... }, ids); 181 } 182 183 // Gets all values for rows that match the given id. 184 template <typename IdTable, typename... ValueTables> 185 static std::vector<std::tuple<SQLite::rowid_t, typename ValueTables::value_t...>> GetAllValuesById(const SQLite::Connection& connection, SQLite::rowid_t id) 186 { 187 auto stmt = details::ManifestTableGetAllValuesByIds_Statement(connection, 188 { SQLite::Builder::QualifiedColumn{ TableName(), SQLite::RowIDName }, SQLite::Builder::QualifiedColumn{ ValueTables::TableName(), ValueTables::ValueName() }... }, 189 { SQLite::Builder::QualifiedColumn{ ValueTables::TableName(), ValueTables::ValueName() }... }, 190 { IdTable::ValueName() }, { id }); 191 std::vector<std::tuple<SQLite::rowid_t, typename ValueTables::value_t...>> result; 192 while (stmt.Step()) 193 { 194 result.emplace_back(stmt.GetRow<SQLite::rowid_t, typename ValueTables::value_t...>()); 195 } 196 return result; 197 } 198 199 // Builds the search select statement base on the given values. 200 // If more than one table is provided, no value will be captured. 201 // The return value is the bind indices of the values to match against. 202 template <typename... Table> 203 static std::vector<int> BuildSearchStatement(SQLite::Builder::StatementBuilder& builder, std::string_view manifestAlias, std::string_view valueAlias, bool useLike) 204 { 205 return details::ManifestTableBuildSearchStatement(builder, { SQLite::Builder::QualifiedColumn{ Table::TableName(), Table::ValueName() }... }, { Table::IsOneToOne()... }, manifestAlias, valueAlias, useLike); 206 } 207 208 // Update the value of a single column for the manifest with the given rowid. 209 template <typename Table> 210 static void UpdateValueIdById(SQLite::Connection& connection, SQLite::rowid_t id, const typename Table::id_t& value) 211 { 212 auto stmt = details::ManifestTableUpdateValueIdById_Statement(connection, details::GetManifestTableColumnName<Table>()); 213 stmt.Bind(1, value); 214 stmt.Bind(2, id); 215 stmt.Execute(); 216 } 217 218 // Deletes the manifest row with the given rowid. 219 static void DeleteById(SQLite::Connection& connection, SQLite::rowid_t id); 220 221 // Removes data that is no longer needed for an index that is to be published. 222 static void PrepareForPackaging(SQLite::Connection& connection, std::initializer_list<std::string_view> values); 223 224 // Removes data that is no longer needed for an index that is to be published. 225 static void PrepareForPackaging_deprecated(SQLite::Connection& connection, std::initializer_list<std::string_view> values); 226 227 // Checks if the row id is present in the column denoted by the value supplied. 228 static bool IsValueReferenced(const SQLite::Connection& connection, std::string_view valueName, SQLite::rowid_t valueRowId); 229 230 // Checks the consistency of the index to ensure that every referenced row exists. 231 // Returns true if index is consistent; false if it is not. 232 template <typename Table> 233 static bool CheckConsistency(const SQLite::Connection& connection, bool log) 234 { 235 return details::ManifestTableCheckConsistency( 236 connection, SQLite::Builder::QualifiedColumn{ Table::TableName(), Table::ValueName() }, details::GetManifestTableColumnName<Table>(), log); 237 } 238 239 // Determines if the table is empty. 240 static bool IsEmpty(SQLite::Connection& connection); 241 }; 242 }