// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chromeos/ash/components/file_manager/indexing/term_table.h"
#include "sql/statement.h"
namespace ash::file_manager {
namespace {
#define TERM_TABLE "term_table"
#define TERM_ID "term_id"
#define FIELD_NAME "field_name"
#define TOKEN_ID "token_id"
// The statement used to create the term table.
static constexpr char kCreateTermTableQuery[] =
// clang-format off
"CREATE TABLE IF NOT EXISTS " TERM_TABLE "("
TERM_ID " INTEGER PRIMARY KEY AUTOINCREMENT,"
FIELD_NAME " TEXT NOT NULL,"
TOKEN_ID " INTEGER NOT NULL REFERENCES term_table(token_id),"
"UNIQUE(" FIELD_NAME ", " TOKEN_ID "))";
// clang-format on
// The statement used to insert a new term into the table.
static constexpr char kInsertTermQuery[] =
// clang-format off
"INSERT OR REPLACE INTO " TERM_TABLE "(" FIELD_NAME ", "
TOKEN_ID ") VALUES (?, ?) RETURNING " TERM_ID;
// clang-format on
// The statement used to delete an term ID from the database by term_id.
static constexpr char kDeleteTermQuery[] =
// clang-format off
"DELETE FROM " TERM_TABLE " WHERE " TERM_ID "=? "
"RETURNING " TERM_ID;
// clang-format on
// The statement used fetch the term ID by field name and token ID.
static constexpr char kGetTermIdQuery[] =
// clang-format off
"SELECT " TERM_ID " FROM " TERM_TABLE " "
"WHERE " FIELD_NAME "=? AND " TOKEN_ID "=?";
// clang-format on
} // namespace
TermTable::TermTable(sql::Database* db) : db_(db) {}
TermTable::~TermTable() = default;
bool TermTable::Init() {
if (!db_->is_open()) {
LOG(WARNING) << "Faield to initialize term_table "
<< "due to closed database";
return false;
}
sql::Statement create_table(
db_->GetCachedStatement(SQL_FROM_HERE, kCreateTermTableQuery));
DCHECK(create_table.is_valid()) << "Invalid create the table statement: \""
<< create_table.GetSQLStatement() << "\"";
if (!create_table.Run()) {
LOG(ERROR) << "Failed to create term_table";
return false;
}
return true;
}
int64_t TermTable::GetTermId(const std::string& field_name,
int64_t token_id) const {
sql::Statement get_term_id(
db_->GetCachedStatement(SQL_FROM_HERE, kGetTermIdQuery));
DCHECK(get_term_id.is_valid()) << "Invalid get term ID statement: \""
<< get_term_id.GetSQLStatement() << "\"";
get_term_id.BindString(0, field_name);
get_term_id.BindInt64(1, token_id);
if (get_term_id.Step()) {
return get_term_id.ColumnInt64(0);
}
return -1;
}
int64_t TermTable::GetOrCreateTermId(const std::string& field_name,
int64_t token_id) {
int64_t term_id = GetTermId(field_name, token_id);
if (term_id != -1) {
return term_id;
}
sql::Statement insert_term(
db_->GetCachedStatement(SQL_FROM_HERE, kInsertTermQuery));
DCHECK(insert_term.is_valid()) << "Invalid insert term statement: \""
<< insert_term.GetSQLStatement() << "\"";
insert_term.BindString(0, field_name);
insert_term.BindInt64(1, token_id);
if (insert_term.Step()) {
return insert_term.ColumnInt64(0);
}
LOG(ERROR) << "Failed to insert term " << field_name << ":" << token_id;
return -1;
}
int64_t TermTable::DeleteTermById(int64_t term_id) {
sql::Statement delete_term(
db_->GetCachedStatement(SQL_FROM_HERE, kDeleteTermQuery));
DCHECK(delete_term.is_valid()) << "Invalid delete term statement: \""
<< delete_term.GetSQLStatement() << "\"";
delete_term.BindInt64(0, term_id);
if (!delete_term.Step()) {
if (!delete_term.Succeeded()) {
LOG(ERROR) << "Failed to delete term " << term_id;
}
return -1;
}
return delete_term.ColumnInt64(0);
}
} // namespace ash::file_manager