chromium/chrome/browser/ash/app_list/search/local_image_search/sql_database.h

// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_ASH_APP_LIST_SEARCH_LOCAL_IMAGE_SEARCH_SQL_DATABASE_H_
#define CHROME_BROWSER_ASH_APP_LIST_SEARCH_LOCAL_IMAGE_SEARCH_SQL_DATABASE_H_

#include <memory>
#include <string>

#include "base/files/file_path.h"
#include "base/functional/callback.h"
#include "base/sequence_checker.h"
#include "base/strings/cstring_view.h"
#include "sql/database.h"
#include "sql/meta_table.h"

namespace sql {
class Statement;
class StatementID;
}  // namespace sql

namespace app_list {

// A database wrapper used initialize a database and maintain a table schema.
// For use on a single sequence/thread.
class SqlDatabase {
 public:
  SqlDatabase(
      const base::FilePath& path_to_db,
      const std::string& histogram_tag,
      int current_version_number,
      base::RepeatingCallback<int(SqlDatabase* db)> create_table_schema,
      base::RepeatingCallback<int(SqlDatabase* db, int current_version_number)>
          migrate_table_schema);

  ~SqlDatabase();
  SqlDatabase(const SqlDatabase&) = delete;
  SqlDatabase& operator=(const SqlDatabase&) = delete;

  // Opens or initializes the database.
  [[nodiscard]] bool Initialize();

  // Must be called in the same sequence with `Initialize()`.
  void Close();

  // Allows us to interact with the database. If the database is open, returns
  // a statement that can Bind* and Run(), otherwise nullptr.
  std::unique_ptr<sql::Statement> GetStatementForQuery(
      const sql::StatementID& sql_from_here,
      base::cstring_view query);

  base::FilePath GetPathToDb() const;

 private:
  void OnErrorCallback(int error, sql::Statement* stmt);
  bool MigrateDatabaseSchema();
  bool RazeDb();

  // The `create_table_schema` called when a new database is constructed. The
  // function must return the `current_version_number`.
  base::RepeatingCallback<int(SqlDatabase* db)> create_table_schema_;

  // The `migrate_table_schema` called when a database with an old schema is
  // open, which needs migrating. The function parameter
  // `current_version_number` is the current old version, which was loaded from
  // the SSD. The function must return the new `current_version_number`
  base::RepeatingCallback<int(SqlDatabase* db, int current_version_number)>
      migrate_table_schema_;

  // The path to the *.db file.
  const base::FilePath path_to_db_;

  // The identifying prefix for metrics.
  const std::string histogram_tag_;

  sql::Database db_;
  sql::MetaTable meta_table_;

  // The current schema version number of the database. It must be greater than
  // 1. Due to the implementation constraint of `sql::MetaTable` the version
  // cannot be zero. Yet a new metatable created for a new uninitialized
  // db has version 1 assigned. So to deduce when we need to call
  // `create_table_schema_` or `migrate_table_schema` the
  // `current_version_number_` must be greater than 1.
  const int current_version_number_;

  SEQUENCE_CHECKER(sequence_checker_);
};
}  // namespace app_list

#endif  // CHROME_BROWSER_ASH_APP_LIST_SEARCH_LOCAL_IMAGE_SEARCH_SQL_DATABASE_H_