#include "data_fake.h"
#include <algorithm>
#include <string_view>
#include <utility>
namespace
{
mw::Error readOnlyError(std::string_view operation)
{
return mw::runtimeError(
"DataSourceFake is read-only and cannot " +
std::string(operation) + ".");
}
bool identitiesMatch(const CardIdentity& left, const CardIdentity& right)
{
return left.game_short_name == right.game_short_name &&
left.card_number == right.card_number;
}
} // namespace
DataSourceFake::DataSourceFake(
std::vector<Card> cards,
std::vector<Series> series,
std::unordered_map<std::int64_t, std::vector<std::int64_t>> card_series,
std::vector<GameDefinitionSnapshot> game_definitions,
std::unordered_map<std::int64_t, std::vector<GameFieldValue>> field_values)
: cards_(std::move(cards)),
series_(std::move(series)),
card_series_(std::move(card_series)),
game_definitions_(std::move(game_definitions)),
field_values_(std::move(field_values))
{}
mw::E<std::int64_t> DataSourceFake::getSchemaVersion() const
{
return DB_SCHEMA_VERSION;
}
mw::E<void> DataSourceFake::migrateSchema0To1()
{
return std::unexpected(readOnlyError("migrate the schema"));
}
mw::E<std::unique_ptr<DataSourceTransactionInterface>>
DataSourceFake::beginTransaction()
{
return std::unexpected(readOnlyError("begin a transaction"));
}
bool DataSourceFake::gameVisible(
const std::string& short_name, GameContentScope scope) const
{
if(scope == GameContentScope::INCLUDE_INTERNAL)
{
return true;
}
const auto definition = std::ranges::find_if(
game_definitions_,
[&short_name](const GameDefinitionSnapshot& candidate)
{
return candidate.game.short_name == short_name;
});
return definition != game_definitions_.end() &&
definition->game.visibility == GameVisibility::PUBLIC;
}
bool DataSourceFake::cardVisible(
const Card& card, GameContentScope scope) const
{
return !card.identity.game_short_name ||
gameVisible(*card.identity.game_short_name, scope);
}
mw::E<std::vector<Card>> DataSourceFake::getCards(
GameContentScope scope) const
{
std::vector<Card> cards;
std::ranges::copy_if(
cards_, std::back_inserter(cards),
[this, scope](const Card& card)
{
return cardVisible(card, scope);
});
return cards;
}
mw::E<std::vector<Card>> DataSourceFake::getCardsByCreator(
std::int64_t creator_user_id, GameContentScope scope) const
{
std::vector<Card> cards;
std::ranges::copy_if(
cards_, std::back_inserter(cards),
[this, creator_user_id, scope](const Card& card)
{
return card.creator_user_id == creator_user_id &&
cardVisible(card, scope);
});
return cards;
}
mw::E<std::optional<Card>> DataSourceFake::getCard(
const CardIdentity& identity, GameContentScope scope) const
{
const auto card = std::ranges::find_if(
cards_,
[&identity](const Card& candidate)
{
return identitiesMatch(candidate.identity, identity);
});
if(card == cards_.end() || !cardVisible(*card, scope))
{
return std::nullopt;
}
return *card;
}
mw::E<std::vector<Game>> DataSourceFake::getGames(
GameContentScope scope) const
{
std::vector<Game> games;
games.reserve(game_definitions_.size());
for(const GameDefinitionSnapshot& definition : game_definitions_)
{
if(gameVisible(definition.game.short_name, scope))
{
games.push_back(definition.game);
}
}
std::ranges::sort(
games,
[](const Game& left, const Game& right)
{
if(left.display_name != right.display_name)
{
return left.display_name < right.display_name;
}
return left.short_name < right.short_name;
});
return games;
}
mw::E<std::optional<GameDefinitionSnapshot>>
DataSourceFake::getGameDefinition(
const std::string& short_name, GameContentScope scope) const
{
const auto definition = std::ranges::find_if(
game_definitions_,
[&short_name](const GameDefinitionSnapshot& candidate)
{
return candidate.game.short_name == short_name;
});
if(definition == game_definitions_.end() ||
!gameVisible(short_name, scope))
{
return std::nullopt;
}
return *definition;
}
mw::E<std::optional<CardGameFields>> DataSourceFake::getCardFieldValues(
std::int64_t card_id, GameContentScope scope) const
{
const auto card = std::ranges::find_if(
cards_,
[card_id](const Card& candidate) { return candidate.id == card_id; });
if(card == cards_.end() || !card->identity.game_short_name ||
!cardVisible(*card, scope))
{
return std::nullopt;
}
auto definition = getGameDefinition(
*card->identity.game_short_name, scope);
if(!definition || !*definition)
{
return std::unexpected(mw::runtimeError(
"Fake card references a missing game"));
}
const auto values = field_values_.find(card_id);
return CardGameFields{
std::move(**definition),
values == field_values_.end()
? std::vector<GameFieldValue>{}
: values->second};
}
mw::E<std::vector<Series>> DataSourceFake::getSeries(
GameContentScope scope) const
{
std::vector<Series> series;
std::ranges::copy_if(
series_, std::back_inserter(series),
[this, scope](const Series& item)
{
return gameVisible(item.game_short_name, scope);
});
return series;
}
mw::E<std::optional<Series>> DataSourceFake::getSeries(
std::int64_t series_id, GameContentScope scope) const
{
const auto series = std::ranges::find_if(
series_,
[series_id](const Series& candidate)
{
return candidate.id == series_id;
});
if(series == series_.end() ||
!gameVisible(series->game_short_name, scope))
{
return std::nullopt;
}
return *series;
}
mw::E<std::vector<std::int64_t>> DataSourceFake::getCardSeries(
std::int64_t card_id) const
{
const auto memberships = card_series_.find(card_id);
if(memberships == card_series_.end())
{
return std::vector<std::int64_t>{};
}
return memberships->second;
}
mw::E<void> DataSourceFake::setSchemaVersion(
[[maybe_unused]] std::int64_t version)
{
return std::unexpected(readOnlyError("set the schema version"));
}