blob: 946386e68763a3ea901d437d54ce8831b5f9afdf [file] [log] [blame]
// 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_