Solution: Command

Command Classes

#pragma once

#include <socialdb.h>

#include <string>
#include <variant>
#include <optional>
#include <tuple>
#include <vector>


class SocialDBCommand
{
public:
    virtual ~SocialDBCommand() {}
    virtual void execute(SocialDB&) = 0;
};

class SocialDBInsertCommand : public SocialDBCommand
{
public:
    SocialDBInsertCommand(
        const std::string& svnr, 
        const std::string& firstname, 
        const std::string& lastname)
    : _svnr(svnr),
      _firstname(firstname),
      _lastname(lastname) {}

    virtual void execute(SocialDB&) override;
    void result() const;

private:
    std::string _svnr;
    std::string _firstname;
    std::string _lastname;

    std::optional<SocialDB::NotInserted> _error;
};

class SocialDBFindCommand : public SocialDBCommand
{
public:
    SocialDBFindCommand(const std::string& svnr) : _svnr(svnr) {}

    virtual void execute(SocialDB&) override;
    SocialDB::Person result() const;

private:
    std::string _svnr;
    std::variant<SocialDB::Person, SocialDB::NotFound> _result;
};

class SocialDBDropCommand : public SocialDBCommand
{
public:
    virtual void execute(SocialDB&) override;
    void result() const {}
};

class SocialDBBulkInsertCommand : public SocialDBCommand
{
public:
    SocialDBBulkInsertCommand() = default;
    SocialDBBulkInsertCommand(std::initializer_list<std::tuple<std::string, std::string, std::string>>);

    void add(const SocialDBInsertCommand&);
    virtual void execute(SocialDB&) override;

private:
    std::vector<SocialDBInsertCommand> _commands;
};
#include "social-db-commands.h"


void SocialDBInsertCommand::execute(SocialDB& db)
{
    try {
        db.insert(_svnr, _firstname, _lastname);
    }
    catch (const SocialDB::NotInserted& e) {
        _error = e;
    }
}

void SocialDBInsertCommand::result() const
{
    if (_error)
        throw _error.value();
}

void SocialDBFindCommand::execute(SocialDB& db)
{
    try {
        _result = db.find(_svnr);
    }
    catch (const SocialDB::NotFound& e) {
        _result = e;
    }
}

SocialDB::Person SocialDBFindCommand::result() const
{
    if (const SocialDB::Person* p = std::get_if<SocialDB::Person>(&_result))
        return *p;
    else
        throw std::get<SocialDB::NotFound>(_result);
}

void SocialDBDropCommand::execute(SocialDB& db)
{
    db.drop();
}

SocialDBBulkInsertCommand::SocialDBBulkInsertCommand(
    std::initializer_list<std::tuple<std::string, std::string, std::string>> init)
{
    for (const auto& [svnr, firstname, lastname]: init)
        _commands.push_back(SocialDBInsertCommand(svnr, firstname, lastname));
}

void SocialDBBulkInsertCommand::add(const SocialDBInsertCommand& ic)
{
    _commands.push_back(ic);
}

void SocialDBBulkInsertCommand::execute(SocialDB& db)
{
    for (auto& c: _commands)
        c.execute(db);
}