chromium/ios/chrome/browser/commerce/model/session_proto_db_factory.h

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

#ifndef IOS_CHROME_BROWSER_COMMERCE_MODEL_SESSION_PROTO_DB_FACTORY_H_
#define IOS_CHROME_BROWSER_COMMERCE_MODEL_SESSION_PROTO_DB_FACTORY_H_

#include <memory>

#import "base/no_destructor.h"
#import "components/commerce/core/proto/commerce_subscription_db_content.pb.h"
#import "components/commerce/core/proto/parcel_tracking_db_content.pb.h"
#import "components/keyed_service/ios/browser_state_dependency_manager.h"
#import "components/keyed_service/ios/browser_state_keyed_service_factory.h"
#import "components/leveldb_proto/public/shared_proto_database_client_list.h"
#import "components/session_proto_db/session_proto_db.h"
#import "ios/web/public/browser_state.h"
#import "ios/web/public/thread/web_task_traits.h"
#import "ios/web/public/thread/web_thread.h"

namespace session_proto_db::internal {
const char kCommerceSubscriptionDBFolder[] = "commerce_subscription_db";
const char kParcelTrackingDBFolder[] = "parcel_tracking_db";

template <typename T>
std::unique_ptr<KeyedService> BuildSessionProtoDB(web::BrowserState* state) {
  DCHECK(!state->IsOffTheRecord());

  if (std::is_base_of<
          commerce_subscription_db::CommerceSubscriptionContentProto,
          T>::value) {
    return std::make_unique<SessionProtoDB<T>>(
        state->GetProtoDatabaseProvider(),
        state->GetStatePath().AppendASCII(kCommerceSubscriptionDBFolder),
        leveldb_proto::ProtoDbType::COMMERCE_SUBSCRIPTION_DATABASE,
        web::GetUIThreadTaskRunner({}));
  } else if (std::is_base_of<parcel_tracking_db::ParcelTrackingContent,
                             T>::value) {
    return std::make_unique<SessionProtoDB<T>>(
        state->GetProtoDatabaseProvider(),
        state->GetStatePath().AppendASCII(kParcelTrackingDBFolder),
        leveldb_proto::ProtoDbType::COMMERCE_PARCEL_TRACKING_DATABASE,
        web::GetUIThreadTaskRunner({}));
  } else {
    // Must add in leveldb_proto::ProtoDbType and database directory folder
    // new protos.
    DCHECK(false) << "Provided template is not supported. To support add "
                     "unique folder in the above proto -> folder name mapping. "
                     "This check could also fail because the template is not "
                     "supported on current platform.";
  }
}
}  // namespace session_proto_db::internal

template <typename T>
class SessionProtoDBFactory : public BrowserStateKeyedServiceFactory {
 public:
  SessionProtoDBFactory(const SessionProtoDBFactory&) = delete;
  SessionProtoDBFactory& operator=(const SessionProtoDBFactory&) = delete;

  static SessionProtoDBFactory<T>* GetInstance();
  static SessionProtoDB<T>* GetForBrowserState(web::BrowserState* state);

  static TestingFactory GetDefaultFactory();

 private:
  friend class base::NoDestructor<SessionProtoDBFactory<T>>;

  SessionProtoDBFactory();
  ~SessionProtoDBFactory() override = default;

  std::unique_ptr<KeyedService> BuildServiceInstanceFor(
      web::BrowserState* state) const override;
};

// static
template <typename T>
SessionProtoDB<T>* SessionProtoDBFactory<T>::GetForBrowserState(
    web::BrowserState* state) {
  // Incognito is currently not supported
  if (state->IsOffTheRecord()) {
    return nullptr;
  }

  return static_cast<SessionProtoDB<T>*>(
      GetInstance()->GetServiceForBrowserState(state, true));
}

template <typename T>
BrowserStateKeyedServiceFactory::TestingFactory
SessionProtoDBFactory<T>::GetDefaultFactory() {
  return base::BindRepeating(
      &session_proto_db::internal::BuildSessionProtoDB<T>);
}

template <typename T>
SessionProtoDBFactory<T>::SessionProtoDBFactory()
    : BrowserStateKeyedServiceFactory(
          "SessionProtoDB",
          BrowserStateDependencyManager::GetInstance()) {}

template <typename T>
std::unique_ptr<KeyedService> SessionProtoDBFactory<T>::BuildServiceInstanceFor(
    web::BrowserState* state) const {
  return session_proto_db::internal::BuildSessionProtoDB<T>(state);
}

// Ensure all SessionProtoDB<T> factories are built for all values of T.
void EnsureSessionProtoDBFactoriesBuilt();

#endif  // IOS_CHROME_BROWSER_COMMERCE_MODEL_SESSION_PROTO_DB_FACTORY_H_