blob: ec62f026851639953dd905bc0231ef5ccf081147 [file] [log] [blame]
// Copyright 2018 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.
#include "chrome/browser/android/explore_sites/get_catalog_task.h"
#include "chrome/browser/android/explore_sites/explore_sites_schema.h"
#include "sql/database.h"
#include "sql/meta_table.h"
#include "sql/statement.h"
#include "sql/transaction.h"
namespace explore_sites {
namespace {
static const char kSelectCategorySql[] = R"(
SELECT category_id, type, label FROM categories
WHERE version = ?
ORDER BY category_id ASC;
)";
static const char kSelectSiteSql[] = R"(
SELECT site_id, url, title FROM sites
WHERE category_id = ?
)";
const char kDeleteSiteSql[] = R"(
DELETE FROM sites WHERE category_id NOT IN
(SELECT category_id FROM categories WHERE version = ?);)";
const char kDeleteCategorySql[] = R"(
DELETE FROM categories WHERE version <> ?;
)";
} // namespace
int64_t UpdateCurrentCatalogIfNewer(sql::MetaTable* meta_table,
int64_t current_catalog_timestamp) {
DCHECK(meta_table);
int64_t downloading_catalog_timestamp = -1LL;
if (!meta_table->GetValue("downloading_catalog",
&downloading_catalog_timestamp) ||
downloading_catalog_timestamp < 0 ||
downloading_catalog_timestamp <= current_catalog_timestamp) {
return current_catalog_timestamp;
}
if (!meta_table->SetValue("current_catalog", downloading_catalog_timestamp))
return -1;
meta_table->DeleteKey("downloading_catalog");
return downloading_catalog_timestamp;
}
void RemoveOutdatedCatalogEntries(sql::Database* db, int64_t timestamp) {
sql::Statement delete_sites(
db->GetCachedStatement(SQL_FROM_HERE, kDeleteSiteSql));
delete_sites.BindInt64(0, timestamp);
delete_sites.Run();
sql::Statement delete_categories(
db->GetCachedStatement(SQL_FROM_HERE, kDeleteCategorySql));
delete_categories.BindInt64(0, timestamp);
delete_categories.Run();
}
std::unique_ptr<GetCatalogTask::CategoryList> GetCatalogSync(
bool update_current,
sql::Database* db) {
DCHECK(db);
sql::MetaTable meta_table;
if (!ExploreSitesSchema::InitMetaTable(db, &meta_table))
return nullptr;
// If we are downloading a catalog that is the same version as the one
// currently in use, don't change it. This is an error, should have been
// caught before we got here.
int64_t catalog_timestamp = 0;
meta_table.GetValue("current_catalog", &catalog_timestamp);
if (update_current) {
sql::Transaction transaction(db);
transaction.Begin();
catalog_timestamp =
UpdateCurrentCatalogIfNewer(&meta_table, catalog_timestamp);
RemoveOutdatedCatalogEntries(db, catalog_timestamp);
if (!transaction.Commit())
return nullptr;
}
sql::Statement category_statement(
db->GetCachedStatement(SQL_FROM_HERE, kSelectCategorySql));
category_statement.BindInt64(0, catalog_timestamp);
auto result = std::make_unique<GetCatalogTask::CategoryList>();
while (category_statement.Step()) {
result->emplace_back(category_statement.ColumnInt(0), // category_id
catalog_timestamp,
category_statement.ColumnInt(1), // type
category_statement.ColumnString(2)); // label
}
if (!category_statement.Succeeded())
return nullptr;
for (auto& category : *result) {
sql::Statement site_statement(
db->GetCachedStatement(SQL_FROM_HERE, kSelectSiteSql));
site_statement.BindInt64(0, category.category_id);
while (site_statement.Step()) {
category.sites.emplace_back(site_statement.ColumnInt(0), // site_id
category.category_id,
GURL(site_statement.ColumnString(1)), // url
site_statement.ColumnString(2)); // title
}
if (!site_statement.Succeeded())
return nullptr;
}
return result;
}
GetCatalogTask::GetCatalogTask(ExploreSitesStore* store,
bool update_current,
CatalogCallback callback)
: store_(store),
update_current_(update_current),
callback_(std::move(callback)),
weak_ptr_factory_(this) {}
GetCatalogTask::~GetCatalogTask() = default;
void GetCatalogTask::Run() {
store_->Execute(base::BindOnce(&GetCatalogSync, update_current_),
base::BindOnce(&GetCatalogTask::FinishedExecuting,
weak_ptr_factory_.GetWeakPtr()),
std::unique_ptr<CategoryList>());
}
void GetCatalogTask::FinishedExecuting(
std::unique_ptr<CategoryList> categories) {
TaskComplete();
DVLOG(1) << "Finished getting the catalog, result: " << categories.get();
std::move(callback_).Run(std::move(categories));
}
} // namespace explore_sites