| // Copyright 2017 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #ifndef COMPONENTS_SQLITE_PROTO_KEY_VALUE_TABLE_H_ | 
 | #define COMPONENTS_SQLITE_PROTO_KEY_VALUE_TABLE_H_ | 
 |  | 
 | #include <map> | 
 | #include <string> | 
 | #include <vector> | 
 |  | 
 | #include "sql/statement.h" | 
 |  | 
 | namespace google { | 
 | namespace protobuf { | 
 | class MessageLite; | 
 | } | 
 | }  // namespace google | 
 |  | 
 | namespace sqlite_proto { | 
 |  | 
 | namespace internal { | 
 |  | 
 | void BindDataToStatement(const std::string& key, | 
 |                          const google::protobuf::MessageLite& data, | 
 |                          sql::Statement* statement); | 
 |  | 
 | std::string GetSelectAllSql(const std::string& table_name); | 
 | std::string GetReplaceSql(const std::string& table_name); | 
 | std::string GetDeleteSql(const std::string& table_name); | 
 | std::string GetDeleteAllSql(const std::string& table_name); | 
 |  | 
 | }  // namespace internal | 
 |  | 
 | // The backend class helps perform database operations on a single table. The | 
 | // table name is passed as a constructor argument. The table schema is fixed: it | 
 | // always consists of two columns, TEXT type "key" and BLOB type "proto". The | 
 | // class doesn't manage the creation and the deletion of the table. | 
 | // | 
 | // All the functions except of the constructor must be called on a DB sequence | 
 | // of the corresponding TableManager. The preferred way to call the methods of | 
 | // this class is passing the method to TableManager::ScheduleDBTask(). | 
 | // | 
 | // Example: | 
 | // manager_->ScheduleDBTask( | 
 | //     FROM_HERE, | 
 | //     base::BindOnce(&KeyValueTable<PrefetchData>::UpdateData, | 
 | //                    table_->AsWeakPtr(), key, data)); | 
 | // | 
 | // TODO(crbug.com/1115398): Supporting weak pointers is a temporary measure | 
 | // mitigating a crash caused by complex lifetime requirements for KeyValueTable | 
 | // relative to the related classes. Making KeyValueTable<T> stateless instead | 
 | // could be a better way to resolve these lifetime issues in the long run. | 
 | template <typename T> | 
 | class KeyValueTable : public base::SupportsWeakPtr<KeyValueTable<T>> { | 
 |  public: | 
 |   explicit KeyValueTable(const std::string& table_name); | 
 |   // Virtual for testing. | 
 |   virtual ~KeyValueTable() = default; | 
 |  | 
 |   KeyValueTable(const KeyValueTable&) = delete; | 
 |   KeyValueTable& operator=(const KeyValueTable&) = delete; | 
 |  | 
 |   virtual void GetAllData(std::map<std::string, T>* data_map, | 
 |                           sql::Database* db) const; | 
 |   virtual void UpdateData(const std::string& key, | 
 |                           const T& data, | 
 |                           sql::Database* db); | 
 |   virtual void DeleteData(const std::vector<std::string>& keys, | 
 |                           sql::Database* db); | 
 |   virtual void DeleteAllData(sql::Database* db); | 
 |  | 
 |  private: | 
 |   const std::string table_name_; | 
 | }; | 
 |  | 
 | template <typename T> | 
 | KeyValueTable<T>::KeyValueTable(const std::string& table_name) | 
 |     : table_name_(table_name) {} | 
 |  | 
 | template <typename T> | 
 | void KeyValueTable<T>::GetAllData(std::map<std::string, T>* data_map, | 
 |                                   sql::Database* db) const { | 
 |   sql::Statement reader(db->GetUniqueStatement( | 
 |       ::sqlite_proto::internal::GetSelectAllSql(table_name_).c_str())); | 
 |   while (reader.Step()) { | 
 |     auto it = data_map->emplace(reader.ColumnString(0), T()).first; | 
 |     int size = reader.ColumnByteLength(1); | 
 |     const void* blob = reader.ColumnBlob(1); | 
 |     // Annoyingly, a nullptr result means either that an error occurred or that | 
 |     // the blob was empty; partially disambiguate based on the length. | 
 |     DCHECK(size && blob || !size && !blob) << !!size << !!blob; | 
 |     it->second.ParseFromArray(blob, size); | 
 |   } | 
 | } | 
 |  | 
 | template <typename T> | 
 | void KeyValueTable<T>::UpdateData(const std::string& key, | 
 |                                   const T& data, | 
 |                                   sql::Database* db) { | 
 |   sql::Statement inserter(db->GetUniqueStatement( | 
 |       ::sqlite_proto::internal::GetReplaceSql(table_name_).c_str())); | 
 |   ::sqlite_proto::internal::BindDataToStatement(key, data, &inserter); | 
 |   inserter.Run(); | 
 | } | 
 |  | 
 | template <typename T> | 
 | void KeyValueTable<T>::DeleteData(const std::vector<std::string>& keys, | 
 |                                   sql::Database* db) { | 
 |   sql::Statement deleter(db->GetUniqueStatement( | 
 |       ::sqlite_proto::internal::GetDeleteSql(table_name_).c_str())); | 
 |   for (const auto& key : keys) { | 
 |     deleter.BindString(0, key); | 
 |     deleter.Run(); | 
 |     deleter.Reset(true); | 
 |   } | 
 | } | 
 |  | 
 | template <typename T> | 
 | void KeyValueTable<T>::DeleteAllData(sql::Database* db) { | 
 |   sql::Statement deleter(db->GetUniqueStatement( | 
 |       ::sqlite_proto::internal::GetDeleteAllSql(table_name_).c_str())); | 
 |   deleter.Run(); | 
 | } | 
 |  | 
 | }  // namespace sqlite_proto | 
 |  | 
 | #endif  // COMPONENTS_SQLITE_PROTO_KEY_VALUE_TABLE_H_ |