PackagesTable.h (8998B)
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 <initializer_list> 7 #include <optional> 8 #include <string_view> 9 #include <utility> 10 #include <vector> 11 12 13 namespace AppInstaller::Repository::Microsoft::Schema::V2_0 14 { 15 namespace details 16 { 17 // Info on the columns. 18 struct ColumnInfo 19 { 20 template<typename Column> 21 static constexpr ColumnInfo Create() 22 { 23 ColumnInfo result; 24 result.Name = Column::Name; 25 result.Type = Column::Type; 26 result.PrimaryKey = Column::PrimaryKey; 27 result.AllowNull = Column::AllowNull; 28 return result; 29 } 30 31 std::string_view Name; 32 SQLite::Builder::Type Type = {}; 33 bool PrimaryKey = false; 34 bool AllowNull = false; 35 }; 36 37 // Creates the table. 38 void PackagesTableCreate(SQLite::Connection& connection, std::initializer_list<ColumnInfo> values); 39 40 // Gets the requested values for the manifest with the given rowid. 41 SQLite::Statement PackagesTableGetValuesById_Statement( 42 const SQLite::Connection& connection, 43 SQLite::rowid_t id, 44 std::initializer_list<std::string_view> columns, 45 bool stepAndVerify = true); 46 47 // Prepares a statement to update the value of a single column for the manifest with the given rowid. 48 // The first bind value will be the value to set. 49 // The second bind value will be the manifest rowid to modify. 50 SQLite::Statement PackagesTableUpdateValueIdById_Statement(SQLite::Connection& connection, std::string_view valueName); 51 52 // Removes data that is no longer needed for an index that is to be published. 53 void PackagesTablePrepareForPackaging(SQLite::Connection& connection, std::initializer_list<ColumnInfo> values); 54 55 // Checks for embedded nulls in the database. 56 bool PackagesTableCheckConsistency(const SQLite::Connection& connection, std::initializer_list<std::string_view> values, bool log); 57 } 58 59 // A table in which each row represents a single package. 60 struct PackagesTable 61 { 62 // Get the table name. 63 static std::string_view TableName(); 64 65 struct IdColumn 66 { 67 static constexpr std::string_view Name = "id"sv; 68 static constexpr SQLite::Builder::Type Type = SQLite::Builder::Type::Text; 69 static constexpr bool PrimaryKey = true; 70 static constexpr bool AllowNull = false; 71 }; 72 73 struct NameColumn 74 { 75 static constexpr std::string_view Name = "name"sv; 76 static constexpr SQLite::Builder::Type Type = SQLite::Builder::Type::Text; 77 static constexpr bool PrimaryKey = false; 78 static constexpr bool AllowNull = false; 79 }; 80 81 struct MonikerColumn 82 { 83 static constexpr std::string_view Name = "moniker"sv; 84 static constexpr SQLite::Builder::Type Type = SQLite::Builder::Type::Text; 85 static constexpr bool PrimaryKey = false; 86 static constexpr bool AllowNull = true; 87 }; 88 89 struct LatestVersionColumn 90 { 91 static constexpr std::string_view Name = "latest_version"sv; 92 static constexpr SQLite::Builder::Type Type = SQLite::Builder::Type::Text; 93 static constexpr bool PrimaryKey = false; 94 static constexpr bool AllowNull = false; 95 }; 96 97 struct ARPMinVersionColumn 98 { 99 static constexpr std::string_view Name = "arp_min_version"sv; 100 static constexpr SQLite::Builder::Type Type = SQLite::Builder::Type::Text; 101 static constexpr bool PrimaryKey = false; 102 static constexpr bool AllowNull = true; 103 }; 104 105 struct ARPMaxVersionColumn 106 { 107 static constexpr std::string_view Name = "arp_max_version"sv; 108 static constexpr SQLite::Builder::Type Type = SQLite::Builder::Type::Text; 109 static constexpr bool PrimaryKey = false; 110 static constexpr bool AllowNull = true; 111 }; 112 113 struct HashColumn 114 { 115 static constexpr std::string_view Name = "hash"sv; 116 static constexpr SQLite::Builder::Type Type = SQLite::Builder::Type::Blob; 117 static constexpr bool PrimaryKey = false; 118 static constexpr bool AllowNull = true; 119 }; 120 121 using ColumnInfo = details::ColumnInfo; 122 123 // Creates the table. 124 template <typename... Columns> 125 static void Create(SQLite::Connection& connection) 126 { 127 details::PackagesTableCreate(connection, { ColumnInfo::Create<Columns>()... }); 128 } 129 130 // Drops the table. 131 static void Drop(SQLite::Connection& connection); 132 133 // Determine if the table currently exists in the database. 134 static bool Exists(const SQLite::Connection& connection); 135 136 // Alters the table, adding the column provided. 137 static void AddColumn(SQLite::Connection& connection, const ColumnInfo& value); 138 139 // A string value for the package. 140 struct NameValuePair 141 { 142 std::string_view Name; 143 std::string Value; 144 }; 145 146 // Insert the given values into the table. 147 static SQLite::rowid_t Insert(SQLite::Connection& connection, const std::vector<NameValuePair>& values); 148 149 // Gets a value indicating whether the package with rowid exists. 150 static bool ExistsById(const SQLite::Connection& connection, SQLite::rowid_t rowid); 151 152 // Gets all row ids from the table. 153 static std::vector<SQLite::rowid_t> GetAllRowIds(const SQLite::Connection& connection, std::string_view orderByColumn, size_t limit = 0); 154 155 // Gets the total number of rows in the table. 156 static uint64_t GetCount(const SQLite::Connection& connection); 157 158 // Gets the values requested for the package with the given rowid. 159 template <typename... Columns> 160 static auto GetValuesById(const SQLite::Connection& connection, SQLite::rowid_t rowid) 161 { 162 return details::PackagesTableGetValuesById_Statement(connection, rowid, { Columns::Name... }).GetRow<typename SQLite::Builder::TypeInfo<Columns::Type, Columns::AllowNull>::value_t...>(); 163 } 164 165 // Gets the value requested for the package with the given rowid, if it exists. 166 template <typename Column> 167 static std::optional<typename SQLite::Builder::TypeInfo<Column::Type, false>::value_t> GetValueById(const SQLite::Connection& connection, SQLite::rowid_t rowid) 168 { 169 auto statement = details::PackagesTableGetValuesById_Statement(connection, rowid, { Column::Name }, false); 170 if (statement.Step()) { return statement.GetColumn<typename SQLite::Builder::TypeInfo<Column::Type, Column::AllowNull>::value_t>(0); } 171 else { return std::nullopt; } 172 } 173 174 // Builds the search select statement base on the given value. 175 // The return value is the bind index of the value to match against. 176 static int BuildSearchStatement(SQLite::Builder::StatementBuilder& builder, std::string_view valueName, std::string_view primaryAlias, std::string_view valueAlias, bool useLike); 177 178 // Update the value of a single column for the package with the given rowid. 179 template <typename Column> 180 static void UpdateValueIdById(SQLite::Connection& connection, SQLite::rowid_t id, const typename SQLite::Builder::TypeInfo<Column::Type, Column::AllowNull>::value_t& value) 181 { 182 auto stmt = details::PackagesTableUpdateValueIdById_Statement(connection, Column::Name); 183 stmt.Bind(1, value); 184 stmt.Bind(2, id); 185 stmt.Execute(); 186 } 187 188 // Removes data that is no longer needed for an index that is to be published. 189 template <typename... Columns> 190 static void PrepareForPackaging(SQLite::Connection& connection) 191 { 192 details::PackagesTablePrepareForPackaging(connection, { ColumnInfo::Create<Columns>()... }); 193 } 194 195 // Checks the consistency of the index to ensure that every referenced row exists. 196 // Returns true if index is consistent; false if it is not. 197 template <typename... Columns> 198 static bool CheckConsistency(const SQLite::Connection& connection, bool log) 199 { 200 return details::PackagesTableCheckConsistency(connection, { Columns::Name... }, log); 201 } 202 203 // Determines if the table is empty. 204 static bool IsEmpty(SQLite::Connection& connection); 205 }; 206 }