added migrations 🔥🚀

Almost everything is implemented, possible to migrate up, down
(rollback), migrate by steps (works for up/down too), reset, refresh,
fresh, wipe database, showing status, installing migration table.

Command line interface is superb, it supports ansi coloring, verbosity,
no-interactive mode, force option, env option to select current env.

It has enhanced ansi coloring (vt100 terminal) detection, when ansi or
no-ansi option is not passed it can detect whether terminal supports
coloring.
Ansi coloring is disabled when redirection to file is detected (can
be overridden by ansi/no-ansi options).
Supports NO_COLOR env. variable (https://no-color.org/) and can detect
the ConEmu, Hyper, and xterm on Windows.

Carefully implemented help and list commands, list command can print
supported commands by namespace.

Advanced make migration command offers great command interface for
creating migration classes, supports options for generating empty,
create, or update migration classes.

Unfinished make project command, will support creating qmake, qmake
subproject, and cmake, cmake subproject projects. Later will be
extracted to own executable tomproject.exe for rapidly generating a new
TinyORM projects.

Other implemented commands are env that prints current env. and inspire
that displays an inspiring quote 😁.

Verbose supports 5 levels quiet, normal, verbose, very verbose, and
debug.

Possibility to disable compilation of the tom command related code using
TINYORM_DISABLE_TOM c macro, for the qmake exists disable_tom CONFIG
option and for the CMake exist TOM configuration option.

Confirmable interface that ask Y/N confirmation during migrate when
env. == production, can be overridden by --force option.

Whole tom terminal application supports or is implemented with UTF-8
support, also implemented UTF-16 output methods but they are not needed.
Input also supports UTF-8, currently only Y/N input is needed by the
Confirmation concern.

All migrate commands also support the --pretend option and the --env
option, when env. is production then tom asks confirmation to migrate,
it can be overridden by the --force option.

Added the tom example project, it is a complete command-line migration
application, it uses migrations from the tests.

Implementing this was really fun 🙃😎.

 - added 14 functional tests to test migrations up/down, stepping,
   installing migration table, refresh, reset on MySQL database
 - added unit test to check version number in tom.exe executable
 - new tom exception classes
 - created dozens of a new todo tasks 😂🤪, currently 348 todos 😎
 - added some info messages to the qmake build about building features
 - in the debug build and with the -vvv option enable debugging of sql
   queries
 - enhanced RC and manifest file generation, allowed to pass a custom
   basename for a RC/manifest file as the 3. argument and a custom
   replace token for the CMake genex as the 4. argument
 - bugfix disabled #pragma code_page(65001) // UTF-8 in RC files, it
   messes up the © character

Output of tom exe without arguments and options:

Common options:
      --ansi            Force ANSI output
      --no-ansi         Disable ANSI output
      --env             The environment the command should run under
  -h, --help            Display help for the given command. When no
                        command is given display help for the list
                        command
  -n, --no-interaction  Do not ask any interactive question
  -q, --quiet           Do not output any message
  -V, --version         Display this application version
  -v|vv|vvv, --verbose  Increase the verbosity of messages: 1 for normal
                        output, 2 for more verbose output and
                        3 for debug

Available commands:
  env                   Display the current framework environment
  help                  Display help for a command
  inspire               Display an inspiring quote
  list                  List commands
  migrate               Run the database migrations
 db
  db:wipe               Drop all tables, views, and types
 make
  make:migration        Create a new migration file
  make:project          Create a new Tom application project
 migrate
  migrate:fresh         Drop all tables and re-run all migrations
  migrate:install       Create the migration repository
  migrate:refresh       Rollback and re-run all migrations
  migrate:reset         Rollback all database migrations
  migrate:rollback      Rollback the last database migration
  migrate:status        Show the status of each migration
This commit is contained in:
silverqx
2022-04-19 20:02:37 +02:00
parent 0290212d36
commit a6213a6a9d
113 changed files with 8276 additions and 290 deletions
+33
View File
@@ -1,5 +1,38 @@
INCLUDEPATH += $$PWD
HEADERS += \
$$PWD/tom/application.hpp \
$$PWD/tom/commands/command.hpp \
$$PWD/tom/commands/database/wipecommand.hpp \
$$PWD/tom/commands/environmentcommand.hpp \
$$PWD/tom/commands/helpcommand.hpp \
$$PWD/tom/commands/inspirecommand.hpp \
$$PWD/tom/commands/listcommand.hpp \
$$PWD/tom/commands/make/migrationcommand.hpp \
# $$PWD/tom/commands/make/projectcommand.hpp \
$$PWD/tom/commands/make/stubs/migrationstubs.hpp \
$$PWD/tom/commands/make/stubs/projectstubs.hpp \
$$PWD/tom/commands/migrations/freshcommand.hpp \
$$PWD/tom/commands/migrations/installcommand.hpp \
$$PWD/tom/commands/migrations/migratecommand.hpp \
$$PWD/tom/commands/migrations/refreshcommand.hpp \
$$PWD/tom/commands/migrations/resetcommand.hpp \
$$PWD/tom/commands/migrations/rollbackcommand.hpp \
$$PWD/tom/commands/migrations/statuscommand.hpp \
$$PWD/tom/concerns/callscommands.hpp \
$$PWD/tom/concerns/confirmable.hpp \
$$PWD/tom/concerns/interactswithio.hpp \
$$PWD/tom/concerns/printsoptions.hpp \
$$PWD/tom/config.hpp \
$$PWD/tom/exceptions/invalidargumenterror.hpp \
$$PWD/tom/exceptions/invalidtemplateargumenterror.hpp \
$$PWD/tom/exceptions/logicerror.hpp \
$$PWD/tom/exceptions/runtimeerror.hpp \
$$PWD/tom/exceptions/tomerror.hpp \
$$PWD/tom/migration.hpp \
$$PWD/tom/migrationcreator.hpp \
$$PWD/tom/migrationrepository.hpp \
$$PWD/tom/migrator.hpp \
$$PWD/tom/terminal.hpp \
$$PWD/tom/tomtypes.hpp \
$$PWD/tom/version.hpp \
-45
View File
@@ -1,45 +0,0 @@
/* This file can't be included in the project, it's for a precompiled header. */
/* Add C includes here */
#if defined __cplusplus
/* Add C++ includes here */
//#include <QDateTime>
//#include <QHash>
//#include <QMap>
//#include <QSharedPointer>
#include <QStringList>
//#include <QTimer>
//#include <QVariant>
#include <QVector>
#include <algorithm>
#include <array>
#include <bitset>
#include <cassert>
#include <cfloat>
#include <cmath>
#include <complex>
#include <condition_variable>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <functional>
#include <initializer_list>
#include <iterator>
#include <map>
#include <memory>
#include <mutex>
#include <numeric>
#include <optional>
#include <set>
#include <span>
#include <string>
//#include <thread>
#include <tuple>
#include <type_traits>
#include <typeinfo>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#endif
-8
View File
@@ -1,8 +0,0 @@
# Use Precompiled headers (PCH)
# ---
PRECOMPILED_HEADER = $$quote($$PWD/pch.h)
HEADERS += $$PRECOMPILED_HEADER
precompile_header: \
DEFINES *= USING_PCH
+264
View File
@@ -0,0 +1,264 @@
#pragma once
#ifndef TOM_APPLICATION_HPP
#define TOM_APPLICATION_HPP
#include <orm/macros/systemheader.hpp>
TINY_SYSTEM_HEADER
#include <QCommandLineParser>
#include "tom/config.hpp"
#include "tom/concerns/interactswithio.hpp"
TINYORM_BEGIN_COMMON_NAMESPACE
namespace Orm
{
class DatabaseManager;
}
namespace Tom {
namespace Commands
{
class Command;
class HelpCommand;
class ListCommand;
} // namespace Commands
namespace Concerns
{
class CallsCommands;
class PrintsOptions;
} // namespace Concerns
class Migration;
class MigrationRepository;
class Migrator;
/*! Tom application. */
class SHAREDLIB_EXPORT Application : public Concerns::InteractsWithIO
{
Q_DISABLE_COPY(Application)
// To access saveOptions()
friend Commands::Command;
// To access createCommand()
friend Commands::HelpCommand;
// To access showVersion()
friend Commands::ListCommand;
// To access m_options
friend Concerns::PrintsOptions;
// To access initializeParser() and createCommand()
friend Concerns::CallsCommands;
/*! Alias for the DatabaseManager. */
using DatabaseManager = Orm::DatabaseManager;
public:
/*! Constructor. */
Application(int &argc, char **argv, std::shared_ptr<DatabaseManager> db,
const char *environmentEnvName = "TOM_ENV",
QString migrationTable = QLatin1String("migrations"),
std::vector<std::shared_ptr<Migration>> migrations = {});
/*! Default destructor. */
inline ~Application() = default;
/*! Instantiate/initialize all migration classes. */
template<typename ...M>
Application &migrations();
/*! Run the tom application. */
int run();
/*! Log exception caught in the main exception handler in a current thread. */
static void logException(const std::exception &e, bool noAnsi = false);
/* Getters / Setters */
/*! Get a current application environment. */
inline const QString &environment() const noexcept;
/*! Get database manager. */
inline DatabaseManager &db() const noexcept;
/*! Get command-line parser. */
inline const QCommandLineParser &parser() const noexcept;
/*! Is the application running in an interactive mode? */
inline bool isInteractive() const noexcept;
/*! Obtain current command-line arguments. */
QStringList arguments() const;
/*! Set the migration repository table name. */
inline Application &migrationTable(QString table);
#ifdef TINYTOM_TESTS_CODE
/*! Alias for the test output row from the status command. */
using StatusRow = std::vector<std::string>;
/*! Get result of the status command (used in auto tests). */
static std::vector<StatusRow> status() noexcept;
/*! Enable logic for unit testing? */
static void enableInUnitTests() noexcept;
#endif
protected:
/*! Alias for the commands' base class. */
using Command = Commands::Command;
/* Application initialization */
#ifdef _WIN32
/*! Prepare console input/output character encoding. */
void initializeConsoleEncoding() const;
#endif
/*! Fix m_argc/m_argv data members if the argv is empty. */
void fixEmptyArgv();
/*! Processes the specified function at application's normal exit. */
void initializeAtExit() const;
/*! Initialize the command-line parser. */
void initializeParser(QCommandLineParser &parser);
/*! Save a copy of application options passed to the Qt's parser. */
const QList<QCommandLineOption> &
saveOptions(QList<QCommandLineOption> &&options);
/*! Prepend command options before common options (used by the help command). */
QList<QCommandLineOption>
prependOptions(QList<QCommandLineOption> &&options);
/* Run command */
/*! Parse current application's command line. */
void parseCommandLine();
/*! Initialize environment value, order:
development -> value from env. variable -> --env command-line argument. */
void initializeEnvironment();
/*! Obtain command name to run. */
QString getCommandName();
/* Early exit during parse command-line */
/*! Display the version information and exits. */
Q_NORETURN void showVersion() const;
/*! Display the version information. */
void printVersion() const;
/*! Invoke the list command. */
Q_NORETURN void showCommandsList(int exitCode);
/*! Exit the application with post routines. */
Q_NORETURN void exitApplication(int exitCode) const;
/* Commands factory */
/*! Alias for an optional command-line parser reference. */
using OptionalParserRef =
std::optional<std::reference_wrapper<QCommandLineParser>>;
/*! Create command by the given name. */
std::unique_ptr<Command>
createCommand(const QString &command, OptionalParserRef parser = std::nullopt,
bool showHelp = true);
/*! Migration repository instance. */
std::shared_ptr<MigrationRepository> createMigrationRepository();
/*! Migrator instance. */
std::shared_ptr<Migrator> createMigrator();
/* Others */
/*! Get all supported commands list (used by the list command). */
const std::vector<std::shared_ptr<Command>> &createCommandsVector();
/*! Get all supported commands' names. */
const std::vector<const char *> &commandNames() const;
/*! Get arguments list from the m_argv array. */
QStringList prepareArguments() const;
/*! Current application argc. */
int &m_argc;
/*! Current application argv. */
char **m_argv;
/*! DatabaseManager instance. */
std::shared_ptr<DatabaseManager> m_db;
/*! The migration repository instance. */
std::shared_ptr<MigrationRepository> m_repository = nullptr;
/*! The migrator service instance. */
std::shared_ptr<Migrator> m_migrator = nullptr;
/* Only one instance can exist in the whole application, auto tests create their
own QCoreApplication instance so this has to be excluded. */
#ifndef TINYTOM_TESTS_CODE
/*! Qt's application instance. */
QCoreApplication m_qtApplication;
/*! Determine whether the TomApplication has its own QCoreApplication instance. */
bool hasQtApplication = true;
#else
/*! Determine whether the TomApplication has its own QCoreApplication instance. */
bool hasQtApplication = false;
#endif
/*! Command line parser. */
QCommandLineParser m_parser {};
/*! Current environment. */
QString m_environment = QStringLiteral("development");
/*! Environment variable name that holds a current environment value. */
const char *m_environmentEnvName;
/*! Migration repository table name. */
QString m_migrationTable;
/*! Migrations vector to process. */
std::vector<std::shared_ptr<Migration>> m_migrations;
/*! Is this input means interactive? */
bool m_interactive = true;
/*! Application options. */
QList<QCommandLineOption> m_options {};
/* Auto tests helpers */
#ifdef TINYTOM_TESTS_CODE
public:
/*! Run the tom application with the given arguments (used in auto tests). */
int runWithArguments(QStringList &&arguments);
#endif
};
/* public */
template<typename ...Migrations>
Application &Application::migrations()
{
m_migrations = {std::make_shared<Migrations>()...};
// Correct sort order is checked in the Migrator::createMigrationNamesMap()
return *this;
}
/* Getters / Setters */
const QString &Application::environment() const noexcept
{
return m_environment;
}
Application::DatabaseManager &Application::db() const noexcept
{
return *m_db;
}
const QCommandLineParser &Application::parser() const noexcept
{
return m_parser;
}
bool Application::isInteractive() const noexcept
{
return m_interactive;
}
Application &Application::migrationTable(QString table)
{
m_migrationTable = std::move(table);
return *this;
}
} // namespace Tom
TINYORM_END_COMMON_NAMESPACE
#endif // TOM_APPLICATION_HPP
+153
View File
@@ -0,0 +1,153 @@
#pragma once
#ifndef TOM_COMMANDS_COMMAND_HPP
#define TOM_COMMANDS_COMMAND_HPP
#include <orm/macros/systemheader.hpp>
TINY_SYSTEM_HEADER
#include "tom/concerns/callscommands.hpp"
#include "tom/concerns/interactswithio.hpp"
TINYORM_BEGIN_COMMON_NAMESPACE
class QCommandLineOption;
namespace Orm
{
class DatabaseConnection;
}
namespace Tom::Commands
{
/*! Positional argument item for a console command. */
struct PositionalArgument
{
/*! Argument name. */
QString name;
/*! Argument description. */
QString description;
/*! Appended to the Usage line, if empty the name is used. */
QString syntax {};
/*! Is argument optional? */
bool optional = false;
/*! Argument's default value (optional argument only). */
QString defaultValue {};
};
/*! Abstract base class for the console command. */
class Command : public Concerns::CallsCommands,
public Concerns::InteractsWithIO
{
Q_DISABLE_COPY(Command)
public:
/*! Constructor. */
Command(Application &application, QCommandLineParser &parser);
/*! Pure virtual destructor. */
inline virtual ~Command() = 0;
/*! The console command name. */
virtual QString name() const = 0;
/*! The console command description. */
virtual QString description() const = 0;
/*! The console command positional arguments signature. */
inline virtual const std::vector<PositionalArgument> &
positionalArguments() const;
/*! The signature of the console command. */
virtual QList<QCommandLineOption> optionsSignature() const;
/*! The console command help. */
inline virtual QString help() const;
/*! Execute the console command. */
virtual int run();
/*! Execute the console command with the given arguments. */
int runWithArguments(QStringList &&arguments);
/* Getters */
/*! Get the tom application. */
inline Application &application() const noexcept;
/*! Determine whether a command has own positional arguments. */
bool hasPositionalArguments() const;
/*! Determine whether a command has own options. */
bool hasOptions() const;
protected:
/* Getters */
/*! Obtain passed arguments to parse (can come from three sources). */
QStringList passedArguments() const;
/* Parser helpers */
/*! Check whether the option name was set in the parser. */
bool isSet(const QString &name) const;
/*! Returns the option value found for the given option name or empty string. */
QString value(const QString &name) const;
/*! Get a full command-line value option if value is set in the parser. */
QString valueCmd(const QString &name, const QString &key = "") const;
/*! Get a full command-line boolean option if it's set in the parser. */
QString boolCmd(const QString &name, const QString &key = "") const;
/*! Check whether a positional argument at the given index was set. */
bool hasArgument(QList<QString>::size_type index) const;
/*! Get a list of positional arguments. */
QStringList arguments() const;
/*! Get a positional argument at the given index position. */
QString argument(QList<QString>::size_type index) const;
/*! Get a positional argument by the given name. */
QString argument(const QString &name) const;
/*! Get a database connection. */
Orm::DatabaseConnection &connection(const QString &name) const;
/*! Get a command-line parser. */
QCommandLineParser &parser() const noexcept;
/*! Reference to the tom application. */
std::reference_wrapper<Application> m_application;
/*! Command line parser. */
std::reference_wrapper<QCommandLineParser> m_parser;
/*! Passed command's arguments. */
QStringList m_arguments {};
/*! Alias for the QList command-line option size type. */
using OptionsSizeType = QList<QCommandLineOption>::size_type;
/*! Map positional argument names to the index for obtaining values. */
std::unordered_map<QString, OptionsSizeType> m_positionalArguments {};
private:
/*! Initialize positional arguments map. */
void initializePositionalArguments();
/*! Show help if --help argument was passed. */
void checkHelpArgument() const;
/*! Show the error wall and exit the application if the parser fails. */
void showParserError(const QCommandLineParser &parser) const;
};
/* public */
Command::~Command() = default;
const std::vector<PositionalArgument> &Command::positionalArguments() const
{
static const std::vector<PositionalArgument> cached;
return cached;
}
QString Command::help() const
{
return {};
}
Application &Command::application() const noexcept
{
return m_application;
}
} // namespace Tom::Commands
TINYORM_END_COMMON_NAMESPACE
#endif // TOM_COMMANDS_COMMAND_HPP
@@ -0,0 +1,67 @@
#pragma once
#ifndef TOM_COMMANDS_DATABASE_WIPECOMMAND_HPP
#define TOM_COMMANDS_DATABASE_WIPECOMMAND_HPP
#include <orm/macros/systemheader.hpp>
TINY_SYSTEM_HEADER
#include "tom/commands/command.hpp"
#include "tom/concerns/confirmable.hpp"
TINYORM_BEGIN_COMMON_NAMESPACE
namespace Tom::Commands::Database
{
/*! Drop all tables, views, and types. */
class WipeCommand : public Command,
public Concerns::Confirmable
{
Q_DISABLE_COPY(WipeCommand)
/*! Alias for the Command. */
using Command = Commands::Command;
public:
/*! Constructor. */
WipeCommand(Application &application, QCommandLineParser &parser);
/*! Virtual destructor. */
inline ~WipeCommand() override = default;
/*! The console command name. */
inline QString name() const override;
/*! The console command description. */
inline QString description() const override;
/*! The signature of the console command. */
QList<QCommandLineOption> optionsSignature() const override;
/*! Execute the console command. */
int run() override;
protected:
/*! Drop all of the database tables. */
void dropAllTables(const QString &database) const;
/*! Drop all of the database views. */
void dropAllViews(const QString &database) const;
/*! Drop all of the database types. */
void dropAllTypes(const QString &database) const;
};
/* public */
QString WipeCommand::name() const
{
return QStringLiteral("db:wipe");
}
QString WipeCommand::description() const
{
return QLatin1String("Drop all tables, views, and types");
}
} // namespace Tom::Commands::Database
TINYORM_END_COMMON_NAMESPACE
#endif // TOM_COMMANDS_DATABASE_WIPECOMMAND_HPP
@@ -0,0 +1,51 @@
#pragma once
#ifndef TOM_COMMANDS_ENVIRONMENTCOMMAND_HPP
#define TOM_COMMANDS_ENVIRONMENTCOMMAND_HPP
#include <orm/macros/systemheader.hpp>
TINY_SYSTEM_HEADER
#include "tom/commands/command.hpp"
TINYORM_BEGIN_COMMON_NAMESPACE
namespace Tom::Commands
{
/*! Display the current environment. */
class EnvironmentCommand : public Command
{
Q_DISABLE_COPY(EnvironmentCommand)
public:
/*! Constructor. */
EnvironmentCommand(Application &application, QCommandLineParser &parser);
/*! Virtual destructor. */
inline ~EnvironmentCommand() override = default;
/*! The console command name. */
inline QString name() const override;
/*! The console command description. */
inline QString description() const override;
/*! Execute the console command. */
int run() override;
};
/* public */
QString EnvironmentCommand::name() const
{
return QStringLiteral("env");
}
QString EnvironmentCommand::description() const
{
return QLatin1String("Display the current framework environment");
}
} // namespace Tom::Commands
TINYORM_END_COMMON_NAMESPACE
#endif // TOM_COMMANDS_ENVIRONMENTCOMMAND_HPP
+85
View File
@@ -0,0 +1,85 @@
#pragma once
#ifndef TOM_COMMANDS_HELPCOMMAND_HPP
#define TOM_COMMANDS_HELPCOMMAND_HPP
#include <orm/macros/systemheader.hpp>
TINY_SYSTEM_HEADER
#include "tom/commands/command.hpp"
#include "tom/concerns/printsoptions.hpp"
TINYORM_BEGIN_COMMON_NAMESPACE
namespace Tom::Commands
{
/*! Display help for a command. */
class HelpCommand : public Command,
public Concerns::PrintsOptions
{
Q_DISABLE_COPY(HelpCommand)
public:
/*! Constructor. */
HelpCommand(Application &application, QCommandLineParser &parser);
/*! Virtual destructor. */
inline ~HelpCommand() override = default;
/*! The console command name. */
inline QString name() const override;
/*! The console command description. */
inline QString description() const override;
/*! The console command positional arguments signature. */
const std::vector<PositionalArgument> &positionalArguments() const override;
/*! The console command help. */
QString help() const override;
/*! Execute the console command. */
int run() override;
protected:
/*! Create command by the given name. */
std::unique_ptr<Command> createCommand(const QString &name) const;
/*! Validate if all required positional arguments are after optional arguments. */
bool validateRequiredArguments(
const std::vector<PositionalArgument> &arguments) const;
/*! Print description section. */
void printDescriptionSection(const Command &command) const;
/*! Print usage section. */
void printUsageSection(
const QString &commandNameArg, const Command &command,
const std::vector<PositionalArgument> &arguments) const;
/*! Print positional arguments section. */
void printArgumentsSection(
const std::vector<PositionalArgument> &arguments) const;
/*! Get max. positional argument size in all command arguments. */
int argumentsMaxSize(const std::vector<PositionalArgument> &arguments) const;
/*! Print a positional's argument default value part. */
void printArgumentDefaultValue(const PositionalArgument &argument) const;
/*! Print options section. */
int printOptionsSection(const Command &command) const;
/*! Print help section. */
void printHelpSection(const Command &command) const;
};
/* public */
QString HelpCommand::name() const
{
return QStringLiteral("help");
}
QString HelpCommand::description() const
{
return QLatin1String("Display help for a command");
}
} // namespace Tom::Commands
TINYORM_END_COMMON_NAMESPACE
#endif // TOM_COMMANDS_HELPCOMMAND_HPP
@@ -0,0 +1,51 @@
#pragma once
#ifndef TOM_COMMANDS_INSPIRECOMMAND_HPP
#define TOM_COMMANDS_INSPIRECOMMAND_HPP
#include <orm/macros/systemheader.hpp>
TINY_SYSTEM_HEADER
#include "tom/commands/command.hpp"
TINYORM_BEGIN_COMMON_NAMESPACE
namespace Tom::Commands
{
/*! Display an inspiring quote. */
class InspireCommand : public Command
{
Q_DISABLE_COPY(InspireCommand)
public:
/*! Constructor. */
InspireCommand(Application &application, QCommandLineParser &parser);
/*! Virtual destructor. */
inline ~InspireCommand() override = default;
/*! The console command name. */
inline QString name() const override;
/*! The console command description. */
inline QString description() const override;
/*! Execute the console command. */
int run() override;
};
/* public */
QString InspireCommand::name() const
{
return QStringLiteral("inspire");
}
QString InspireCommand::description() const
{
return QLatin1String("Display an inspiring quote");
}
} // namespace Tom::Commands
TINYORM_END_COMMON_NAMESPACE
#endif // TOM_COMMANDS_INSPIRECOMMAND_HPP
+89
View File
@@ -0,0 +1,89 @@
#pragma once
#ifndef TOM_COMMANDS_LISTCOMMAND_HPP
#define TOM_COMMANDS_LISTCOMMAND_HPP
#include <orm/macros/systemheader.hpp>
TINY_SYSTEM_HEADER
#include "tom/commands/command.hpp"
#include "tom/concerns/printsoptions.hpp"
TINYORM_BEGIN_COMMON_NAMESPACE
namespace Tom::Commands
{
/*! List all available commands. */
class ListCommand : public Command,
public Concerns::PrintsOptions
{
Q_DISABLE_COPY(ListCommand)
public:
/*! Constructor. */
ListCommand(Application &application, QCommandLineParser &parser);
/*! Virtual destructor. */
inline ~ListCommand() override = default;
/*! The console command name. */
inline QString name() const override;
/*! The console command description. */
inline QString description() const override;
/*! The console command positional arguments signature. */
const std::vector<PositionalArgument> &positionalArguments() const override;
/*! The signature of the console command. */
QList<QCommandLineOption> optionsSignature() const override;
/*! The console command help. */
QString help() const override;
/*! Execute the console command. */
int run() override;
protected:
/*! Output full commands list. */
int full(const QString &namespaceArg);
/*! Output raw commands list and nothing else (can be consumed by scripts). */
int raw(const QString &namespaceArg);
/* Commands section */
/*! Print commands section. */
void printCommandsSection(const QString &namespaceArg, int optionsMaxSize) const;
/*! Get max. command size in all command names. */
int commandsMaxSize(const std::vector<std::shared_ptr<Command>> &commands,
int optionsMaxSize) const;
/*! Print commands to the console. */
void printCommands(const std::vector<std::shared_ptr<Command>> &commands,
int commandsMaxSize, bool hasNamespaceArg) const;
/*! Print a new namespace section. */
void tryBeginNsSection(QString &renderingNamespace,
const QString &commandName, bool hasNamespaceArg) const;
/*! Get command's namespace from a command name. */
QString commandNamespace(const QString &commandName) const;
/*! Wrapper for the two methods below, helps to avoid one copy. */
const std::vector<std::shared_ptr<Command>> &
getCommandsByNamespace(const QString &name) const;
/*! Obtain all commands in the given namespace. */
std::vector<std::shared_ptr<Command>>
getCommandsInNamespace(const QString &name) const;
};
/* public */
QString ListCommand::name() const
{
return QStringLiteral("list");
}
QString ListCommand::description() const
{
return QLatin1String("List commands");
}
} // namespace Tom::Commands
TINYORM_END_COMMON_NAMESPACE
#endif // TOM_COMMANDS_LISTCOMMAND_HPP
@@ -0,0 +1,80 @@
#pragma once
#ifndef TOM_COMMANDS_MAKE_MIGRATIONCOMMAND_HPP
#define TOM_COMMANDS_MAKE_MIGRATIONCOMMAND_HPP
#include <orm/macros/systemheader.hpp>
TINY_SYSTEM_HEADER
#include "tom/commands/command.hpp"
#include "tom/migrationcreator.hpp"
TINYORM_BEGIN_COMMON_NAMESPACE
namespace Tom::Commands::Make
{
/*! Create a new migration file. */
class MigrationCommand : public Command
{
Q_DISABLE_COPY(MigrationCommand)
/*! Alias for the filesystem path. */
using path = std::filesystem::path;
public:
/*! Constructor. */
MigrationCommand(Application &application, QCommandLineParser &parser);
/*! Virtual destructor. */
inline ~MigrationCommand() override = default;
/*! The console command name. */
inline QString name() const override;
/*! The console command description. */
inline QString description() const override;
/*! The console command positional arguments signature. */
const std::vector<PositionalArgument> &positionalArguments() const override;
/*! The signature of the console command. */
QList<QCommandLineOption> optionsSignature() const override;
/*! Execute the console command. */
int run() override;
protected:
/*! Write the migration file to disk. */
void writeMigration(const QString &name, const QString &table,
bool create) const;
/*! Get migration path (either specified by '--path' option or default
location). */
inline path getMigrationPath() const;
/*! The migration creator instance. */
MigrationCreator m_creator {};
};
/* public */
QString MigrationCommand::name() const
{
return QStringLiteral("make:migration");
}
QString MigrationCommand::description() const
{
return QLatin1String("Create a new migration file");
}
/* protected */
// CUR tom, finish --path/--realpath silverqx
std::filesystem::path MigrationCommand::getMigrationPath() const
{
return path(__FILE__).parent_path().parent_path().parent_path() / "migrations";
}
} // namespace Tom::Commands::Make
TINYORM_END_COMMON_NAMESPACE
#endif // TOM_COMMANDS_MAKE_MIGRATIONCOMMAND_HPP
@@ -0,0 +1,78 @@
#pragma once
#ifndef TOM_COMMANDS_MAKE_PROJECTCOMMAND_HPP
#define TOM_COMMANDS_MAKE_PROJECTCOMMAND_HPP
#include <orm/macros/systemheader.hpp>
TINY_SYSTEM_HEADER
#include "tom/commands/command.hpp"
//#include "tom/migrationcreator.hpp"
TINYORM_BEGIN_COMMON_NAMESPACE
namespace Tom::Commands::Make
{
/*! Create a new Tom application project. */
class ProjectCommand : public Command
{
Q_DISABLE_COPY(ProjectCommand)
/*! Alias for the filesystem path. */
// using path = std::filesystem::path;
public:
/*! Constructor. */
ProjectCommand(Application &application, QCommandLineParser &parser);
/*! Virtual destructor. */
inline ~ProjectCommand() override = default;
/*! The console command name. */
inline QString name() const override;
/*! The console command description. */
inline QString description() const override;
/*! The console command positional arguments signature. */
const std::vector<PositionalArgument> &positionalArguments() const override;
/*! The signature of the console command. */
QList<QCommandLineOption> signature() const override;
/*! Execute the console command. */
int run() override;
protected:
/*! Write the migration file to disk. */
// void writeMigration(const QString &name, const QString &table,
// bool create) const;
/*! Get migration path (either specified by '--path' option or default
location). */
// inline path getMigrationPath() const;
/*! The migration creator instance. */
// MigrationCreator m_creator {};
};
/* public */
QString ProjectCommand::name() const
{
return QStringLiteral("make:project");
}
QString ProjectCommand::description() const
{
return QLatin1String("Create a new Tom application project");
}
/* protected */
// std::filesystem::path ProjectCommand::getMigrationPath() const
// {
// return path(__FILE__).parent_path().parent_path().parent_path() / "migrations";
// }
} // namespace Tom::Commands::Make
TINYORM_END_COMMON_NAMESPACE
#endif // TOM_COMMANDS_MAKE_PROJECTCOMMAND_HPP
@@ -0,0 +1,110 @@
#pragma once
#ifndef TOM_COMMANDS_MAKE_STUBS_MIGRATIONSTUBS_HPP
#define TOM_COMMANDS_MAKE_STUBS_MIGRATIONSTUBS_HPP
#include <orm/macros/systemheader.hpp>
TINY_SYSTEM_HEADER
#include <orm/macros/commonnamespace.hpp>
TINYORM_BEGIN_COMMON_NAMESPACE
namespace Tom::Commands::Make::Stubs
{
/*! Empty migration stub. */
inline const auto *const MigrationStub = R"T(#pragma once
#include <tom/migration.hpp>
namespace Migrations
{
struct {{ class }} : Migration
{
/*! Run the migrations. */
void up() const override
{
//
}
/*! Reverse the migrations. */
void down() const override
{
//
}
};
} // namespace Migrations
)T";
/*! Migration stub for creating a new table. */
inline const auto *const MigrationCreateStub = R"T(#pragma once
#include <tom/migration.hpp>
namespace Migrations
{
struct {{ class }} : Migration
{
/*! Run the migrations. */
void up() const override
{
Schema::create("{{ table }}", [](Blueprint &table)
{
table.id();
table.timestamps();
});
}
/*! Reverse the migrations. */
void down() const override
{
Schema::dropIfExists("{{ table }}");
}
};
} // namespace Migrations
)T";
/*! Migration stub for updating an existing table. */
inline const auto *const MigrationUpdateStub = R"T(#pragma once
#include <tom/migration.hpp>
namespace Migrations
{
struct {{ class }} : Migration
{
/*! Run the migrations. */
void up() const override
{
Schema::table("{{ table }}", [](Blueprint &table)
{
//
});
}
/*! Reverse the migrations. */
void down() const override
{
Schema::table("{{ table }}", [](Blueprint &table)
{
//
});
}
};
} // namespace Migrations
)T";
} // namespace Tom::Commands::Make::Stubs
TINYORM_END_COMMON_NAMESPACE
#endif // TOM_COMMANDS_MAKE_STUBS_MIGRATIONSTUBS_HPP
@@ -0,0 +1,22 @@
#pragma once
#ifndef TOM_COMMANDS_MAKE_STUBS_PROJECTSTUBS_HPP
#define TOM_COMMANDS_MAKE_STUBS_PROJECTSTUBS_HPP
#include <orm/macros/systemheader.hpp>
TINY_SYSTEM_HEADER
#include <orm/macros/commonnamespace.hpp>
TINYORM_BEGIN_COMMON_NAMESPACE
namespace Tom::Commands::Make::Stubs
{
inline const auto *const XyzStub = R"T(#pragma once
)T";
} // namespace Tom::Commands::Make::Stubs
TINYORM_END_COMMON_NAMESPACE
#endif // TOM_COMMANDS_MAKE_STUBS_PROJECTSTUBS_HPP
@@ -0,0 +1,74 @@
#pragma once
#ifndef TOM_COMMANDS_MIGRATIONS_FRESHCOMMAND_HPP
#define TOM_COMMANDS_MIGRATIONS_FRESHCOMMAND_HPP
#include <orm/macros/systemheader.hpp>
TINY_SYSTEM_HEADER
#include "tom/commands/command.hpp"
#include "tom/concerns/confirmable.hpp"
TINYORM_BEGIN_COMMON_NAMESPACE
namespace Tom
{
class Migrator;
namespace Commands::Migrations
{
/*! Rollback the last database migration/s. */
class FreshCommand : public Command,
public Concerns::Confirmable
{
Q_DISABLE_COPY(FreshCommand)
/*! Alias for the Command. */
using Command = Commands::Command;
public:
/*! Constructor. */
FreshCommand(Application &application, QCommandLineParser &parser,
std::shared_ptr<Migrator> migrator);
/*! Virtual destructor. */
inline ~FreshCommand() override = default;
/*! The console command name. */
inline QString name() const override;
/*! The console command description. */
inline QString description() const override;
/*! The signature of the console command. */
QList<QCommandLineOption> optionsSignature() const override;
/*! Execute the console command. */
int run() override;
protected:
/*! Determine if the developer has requested database seeding. */
bool needsSeeding() const;
/*! Run the database seeder command. */
void runSeeder(QString &&databaseCmd) const;
/*! The migrator service instance. */
std::shared_ptr<Migrator> m_migrator;
};
/* public */
QString FreshCommand::name() const
{
return QStringLiteral("migrate:fresh");
}
QString FreshCommand::description() const
{
return QLatin1String("Drop all tables and re-run all migrations");
}
} // namespace Commands::Migrations
} // namespace Tom
TINYORM_END_COMMON_NAMESPACE
#endif // TOM_COMMANDS_MIGRATIONS_FRESHCOMMAND_HPP
@@ -0,0 +1,64 @@
#pragma once
#ifndef TOM_COMMANDS_MIGRATIONS_INSTALLCOMMAND_HPP
#define TOM_COMMANDS_MIGRATIONS_INSTALLCOMMAND_HPP
#include <orm/macros/systemheader.hpp>
TINY_SYSTEM_HEADER
#include "tom/commands/command.hpp"
TINYORM_BEGIN_COMMON_NAMESPACE
namespace Tom
{
class MigrationRepository;
namespace Commands::Migrations
{
/*! Create the migration database repository. */
class InstallCommand : public Command
{
Q_DISABLE_COPY(InstallCommand)
public:
/*! Constructor. */
InstallCommand(Application &application, QCommandLineParser &parser,
std::shared_ptr<MigrationRepository> repository);
/*! Virtual destructor. */
inline ~InstallCommand() override = default;
/*! The console command name. */
inline QString name() const override;
/*! The console command description. */
inline QString description() const override;
/*! The signature of the console command. */
QList<QCommandLineOption> optionsSignature() const override;
/*! Execute the console command. */
int run() override;
protected:
/*! The repository instance. */
std::shared_ptr<MigrationRepository> m_repository;
};
/* public */
QString InstallCommand::name() const
{
return QStringLiteral("migrate:install");
}
QString InstallCommand::description() const
{
return QLatin1String("Create the migration repository");
}
} // namespace Commands::Migrations
} // namespace Tom
TINYORM_END_COMMON_NAMESPACE
#endif // TOM_COMMANDS_MIGRATIONS_INSTALLCOMMAND_HPP
@@ -0,0 +1,79 @@
#pragma once
#ifndef TOM_COMMANDS_MIGRATIONS_MIGRATECOMMAND_HPP
#define TOM_COMMANDS_MIGRATIONS_MIGRATECOMMAND_HPP
#include <orm/macros/systemheader.hpp>
TINY_SYSTEM_HEADER
#include "tom/commands/command.hpp"
#include "tom/concerns/confirmable.hpp"
TINYORM_BEGIN_COMMON_NAMESPACE
namespace Tom
{
class Migrator;
namespace Commands::Migrations
{
/*! Run the database migrations up/down. */
class MigrateCommand : public Command,
public Concerns::Confirmable
{
Q_DISABLE_COPY(MigrateCommand)
/*! Alias for the Command. */
using Command = Commands::Command;
public:
/*! Constructor. */
MigrateCommand(Application &application, QCommandLineParser &parser,
std::shared_ptr<Migrator> migrator);
/*! Virtual destructor. */
inline ~MigrateCommand() override = default;
/*! The console command name. */
inline QString name() const override;
/*! The console command description. */
inline QString description() const override;
/*! The signature of the console command. */
QList<QCommandLineOption> optionsSignature() const override;
/*! Execute the console command. */
int run() override;
protected:
/*! Prepare the migration database for running. */
void prepareDatabase() const;
/*! Load the schema state to seed the initial database schema structure. */
void loadSchemaState() const;
/*! Determine if the developer has requested database seeding. */
bool needsSeeding() const;
/*! Run the database seeder command. */
void runSeeder() const;
/*! The migrator service instance. */
std::shared_ptr<Migrator> m_migrator;
};
/* public */
QString MigrateCommand::name() const
{
return QStringLiteral("migrate");
}
QString MigrateCommand::description() const
{
return QLatin1String("Run the database migrations");
}
} // namespace Commands::Migrations
} // namespace Tom
TINYORM_END_COMMON_NAMESPACE
#endif // TOM_COMMANDS_MIGRATIONS_MIGRATECOMMAND_HPP
@@ -0,0 +1,74 @@
#pragma once
#ifndef TOM_COMMANDS_MIGRATIONS_REFRESHCOMMAND_HPP
#define TOM_COMMANDS_MIGRATIONS_REFRESHCOMMAND_HPP
#include <orm/macros/systemheader.hpp>
TINY_SYSTEM_HEADER
#include "tom/commands/command.hpp"
#include "tom/concerns/confirmable.hpp"
TINYORM_BEGIN_COMMON_NAMESPACE
namespace Tom
{
class Migrator;
namespace Commands::Migrations
{
/*! Rollback the last database migration. */
class RefreshCommand : public Command,
public Concerns::Confirmable
{
Q_DISABLE_COPY(RefreshCommand)
/*! Alias for the Command. */
using Command = Commands::Command;
public:
/*! Constructor. */
RefreshCommand(Application &application, QCommandLineParser &parser,
std::shared_ptr<Migrator> migrator);
/*! Virtual destructor. */
inline ~RefreshCommand() override = default;
/*! The console command name. */
inline QString name() const override;
/*! The console command description. */
inline QString description() const override;
/*! The signature of the console command. */
QList<QCommandLineOption> optionsSignature() const override;
/*! Execute the console command. */
int run() override;
protected:
/*! Determine if the developer has requested database seeding. */
bool needsSeeding() const;
/*! Run the database seeder command. */
void runSeeder(QString &&databaseCmd) const;
/*! The migrator service instance. */
std::shared_ptr<Migrator> m_migrator;
};
/* public */
QString RefreshCommand::name() const
{
return QStringLiteral("migrate:refresh");
}
QString RefreshCommand::description() const
{
return QLatin1String("Rollback and re-run all migrations");
}
} // namespace Commands::Migrations
} // namespace Tom
TINYORM_END_COMMON_NAMESPACE
#endif // TOM_COMMANDS_MIGRATIONS_REFRESHCOMMAND_HPP
@@ -0,0 +1,69 @@
#pragma once
#ifndef TOM_COMMANDS_MIGRATIONS_RESETCOMMAND_HPP
#define TOM_COMMANDS_MIGRATIONS_RESETCOMMAND_HPP
#include <orm/macros/systemheader.hpp>
TINY_SYSTEM_HEADER
#include "tom/commands/command.hpp"
#include "tom/concerns/confirmable.hpp"
TINYORM_BEGIN_COMMON_NAMESPACE
namespace Tom
{
class Migrator;
namespace Commands::Migrations
{
/*! Rollback the last database migration. */
class ResetCommand : public Command,
public Concerns::Confirmable
{
Q_DISABLE_COPY(ResetCommand)
/*! Alias for the Command. */
using Command = Commands::Command;
public:
/*! Constructor. */
ResetCommand(Application &application, QCommandLineParser &parser,
std::shared_ptr<Migrator> migrator);
/*! Virtual destructor. */
inline ~ResetCommand() override = default;
/*! The console command name. */
inline QString name() const override;
/*! The console command description. */
inline QString description() const override;
/*! The signature of the console command. */
QList<QCommandLineOption> optionsSignature() const override;
/*! Execute the console command. */
int run() override;
protected:
/*! The migrator service instance. */
std::shared_ptr<Migrator> m_migrator;
};
/* public */
QString ResetCommand::name() const
{
return QStringLiteral("migrate:reset");
}
QString ResetCommand::description() const
{
return QLatin1String("Rollback all database migrations");
}
} // namespace Commands::Migrations
} // namespace Tom
TINYORM_END_COMMON_NAMESPACE
#endif // TOM_COMMANDS_MIGRATIONS_RESETCOMMAND_HPP
@@ -0,0 +1,69 @@
#pragma once
#ifndef TOM_COMMANDS_MIGRATIONS_ROLLBACKCOMMAND_HPP
#define TOM_COMMANDS_MIGRATIONS_ROLLBACKCOMMAND_HPP
#include <orm/macros/systemheader.hpp>
TINY_SYSTEM_HEADER
#include "tom/commands/command.hpp"
#include "tom/concerns/confirmable.hpp"
TINYORM_BEGIN_COMMON_NAMESPACE
namespace Tom
{
class Migrator;
namespace Commands::Migrations
{
/*! Rollback the last database migration. */
class RollbackCommand : public Command,
public Concerns::Confirmable
{
Q_DISABLE_COPY(RollbackCommand)
/*! Alias for the Command. */
using Command = Commands::Command;
public:
/*! Constructor. */
RollbackCommand(Application &application, QCommandLineParser &parser,
std::shared_ptr<Migrator> migrator);
/*! Virtual destructor. */
inline ~RollbackCommand() override = default;
/*! The console command name. */
inline QString name() const override;
/*! The console command description. */
inline QString description() const override;
/*! The signature of the console command. */
QList<QCommandLineOption> optionsSignature() const override;
/*! Execute the console command. */
int run() override;
protected:
/*! The migrator service instance. */
std::shared_ptr<Migrator> m_migrator;
};
/* public */
QString RollbackCommand::name() const
{
return QStringLiteral("migrate:rollback");
}
QString RollbackCommand::description() const
{
return QLatin1String("Rollback the last database migration");
}
} // namespace Commands::Migrations
} // namespace Tom
TINYORM_END_COMMON_NAMESPACE
#endif // TOM_COMMANDS_MIGRATIONS_ROLLBACKCOMMAND_HPP
@@ -0,0 +1,118 @@
#pragma once
#ifndef TOM_COMMANDS_MIGRATIONS_STATUSCOMMAND_HPP
#define TOM_COMMANDS_MIGRATIONS_STATUSCOMMAND_HPP
#include <orm/macros/systemheader.hpp>
TINY_SYSTEM_HEADER
#include <QVariant>
#include <tabulate/table.hpp>
#ifdef TINYTOM_TESTS_CODE
#include <orm/macros/threadlocal.hpp>
#endif
#include "tom/commands/command.hpp"
TINYORM_BEGIN_COMMON_NAMESPACE
namespace Tom
{
class Migrator;
namespace Commands::Migrations
{
/*! Show the status of each migration. */
class StatusCommand : public Command
{
Q_DISABLE_COPY(StatusCommand)
/*! Alias for the tabulate cell. */
using TableCell = InteractsWithIO::TableCell;
/*! Alias for the tabulate row. */
using TableRow = InteractsWithIO::TableRow;
public:
/*! Constructor. */
StatusCommand(Application &application, QCommandLineParser &parser,
std::shared_ptr<Migrator> migrator);
/*! Virtual destructor. */
inline ~StatusCommand() override = default;
/*! The console command name. */
inline QString name() const override;
/*! The console command description. */
inline QString description() const override;
/*! The signature of the console command. */
QList<QCommandLineOption> optionsSignature() const override;
/*! Execute the console command. */
int run() override;
#ifdef TINYTOM_TESTS_CODE
/*! Alias for the test output row. */
using StatusRow = std::vector<std::string>;
/*! Get result of the status command (used in auto tests). */
inline static std::vector<StatusRow> status() noexcept;
/*! Enable logic for unit testing? */
inline static void setInUnitTests() noexcept;
#endif
protected:
/*! Get the status for the given ran migrations. */
std::vector<TableRow>
getStatusFor(QVector<QVariant> &&ran,
std::map<QString, QVariant> &&batches) const;
#ifdef TINYTOM_TESTS_CODE
/*! Transform migrations status for comparing in auto tests. */
std::vector<StatusRow>
statusForUnitTest(std::vector<TableRow> &&migrations) const;
#endif
/*! The migrator service instance. */
std::shared_ptr<Migrator> m_migrator;
#ifdef TINYTOM_TESTS_CODE
/*! Result of the status command (used in auto tests). */
T_THREAD_LOCAL
inline static std::vector<StatusRow> m_status;
/*! Is enabled logic for unit testing? */
T_THREAD_LOCAL
inline static auto m_inUnitTests = false;
#endif
};
/* public */
QString StatusCommand::name() const
{
return QStringLiteral("migrate:status");
}
QString StatusCommand::description() const
{
return QLatin1String("Show the status of each migration");
}
#ifdef TINYTOM_TESTS_CODE
std::vector<StatusCommand::StatusRow> StatusCommand::status() noexcept
{
return m_status;
}
void StatusCommand::setInUnitTests() noexcept
{
m_inUnitTests = true;
}
#endif
} // namespace Commands::Migrations
} // namespace Tom
TINYORM_END_COMMON_NAMESPACE
#endif // TOM_COMMANDS_MIGRATIONS_STATUSCOMMAND_HPP
@@ -0,0 +1,67 @@
#pragma once
#ifndef TOM_CONCERNS_CALLSCOMMANDS_HPP
#define TOM_CONCERNS_CALLSCOMMANDS_HPP
#include <orm/macros/systemheader.hpp>
TINY_SYSTEM_HEADER
#include <QStringList>
#include <orm/macros/commonnamespace.hpp>
TINYORM_BEGIN_COMMON_NAMESPACE
namespace Tom
{
namespace Commands
{
class Command;
}
namespace Concerns
{
/*! Invoke another command by name and passed arguments. */
class CallsCommands
{
Q_DISABLE_COPY(CallsCommands)
public:
/*! Default constructor. */
inline CallsCommands() = default;
/*! Default destructor. */
inline ~CallsCommands() = default;
/*! Call another console command. */
inline int call(const QString &command, QStringList &&arguments = {}) const;
protected:
/*! Run the given console command. */
int runCommand(const QString &command, QStringList &&arguments) const;
/*! Create command-line arguments from the given arguments. */
QStringList
createCommandLineArguments(const QString &command, QStringList &&arguments,
QStringList &&currentArguments) const;
/*! Get common command-line arguments from current command-line arguments. */
QStringList getCommonArguments(QStringList &&arguments) const;
private:
/*! Static cast *this to the Command & derived type, const version. */
const Commands::Command &command() const;
};
/* public */
int CallsCommands::call(const QString &command, QStringList &&arguments) const
{
return runCommand(std::move(command), std::move(arguments));
}
} // namespace Concerns
} // namespace Tom
TINYORM_END_COMMON_NAMESPACE
#endif // TOM_CONCERNS_CALLSCOMMANDS_HPP
+58
View File
@@ -0,0 +1,58 @@
#pragma once
#ifndef TOM_CONCERNS_CONFIRMABLE_HPP
#define TOM_CONCERNS_CONFIRMABLE_HPP
#include <orm/macros/systemheader.hpp>
TINY_SYSTEM_HEADER
#include <QString>
#include <functional>
#include <orm/macros/commonnamespace.hpp>
TINYORM_BEGIN_COMMON_NAMESPACE
namespace Tom
{
namespace Commands
{
class Command;
}
namespace Concerns
{
/*! Prints alert and asks for the confirmation (Y/N). */
class Confirmable
{
Q_DISABLE_COPY(Confirmable)
/*! Alias for the Command. */
using Command = Commands::Command;
public:
/*! Constructor (int param. to avoid interpret it as copy ctor). */
Confirmable(Command &command, int);
/*! Default destructor. */
inline ~Confirmable() = default;
/*! Confirm before proceeding with the action (only in production environment). */
bool confirmToProceed(
const QString &warning = QLatin1String("Application In Production!"),
const std::function<bool()> &callback = nullptr) const;
protected:
/*! Get the default confirmation callback. */
std::function<bool()> defaultConfirmCallback() const;
/*! Reference to a command that should be confimable. */
std::reference_wrapper<Command> m_command;
};
} // namespace Concerns
} // namespace Tom
TINYORM_END_COMMON_NAMESPACE
#endif // TOM_CONCERNS_CONFIRMABLE_HPP
@@ -0,0 +1,238 @@
#pragma once
#ifndef TOM_CONCERNS_INTERACTSWITHIO_HPP
#define TOM_CONCERNS_INTERACTSWITHIO_HPP
#include <orm/macros/systemheader.hpp>
TINY_SYSTEM_HEADER
#include <QStringList>
#include <tabulate/table.hpp>
#include <orm/macros/commonnamespace.hpp>
#include <orm/macros/export.hpp>
TINYORM_BEGIN_COMMON_NAMESPACE
class QCommandLineParser;
namespace Tom
{
class Application;
class Terminal;
namespace Concerns
{
/*! Set of methods for the console output/input. */
class SHAREDLIB_EXPORT InteractsWithIO
{
Q_DISABLE_COPY(InteractsWithIO)
// To access private ctor and errorWallInternal() (used by logException())
friend Tom::Application;
public:
/*! Alias for the tabulate cell. */
using TableCell = std::variant<std::string, tabulate::Table>;
/*! Alias for the tabulate row. */
using TableRow = std::vector<TableCell>;
/*! Constructor. */
explicit InteractsWithIO(const QCommandLineParser &parser);
/*! Default destructor. */
~InteractsWithIO();
/*! Base enum for the verbosity levels. */
enum struct Verbosity {
Quiet = 0x0001,
Normal = 0x0002,
Verbose = 0x0004,
VeryVerbose = 0x0008,
Debug = 0x0010,
};
/*! Quiet verbosity. */
static constexpr Verbosity Quiet = Verbosity::Quiet;
/*! Normal verbosity (default). */
static constexpr Verbosity Normal = Verbosity::Normal;
/*! Verbose verbosity. */
static constexpr Verbosity Verbose = Verbosity::Verbose;
/*! Very verbose verbosity. */
static constexpr Verbosity VeryVerbose = Verbosity::VeryVerbose;
/*! Debug verbosity. */
static constexpr Verbosity Debug = Verbosity::Debug;
/*! Write a string as standard output. */
const InteractsWithIO &line(const QString &string, bool newline = true,
Verbosity verbosity = Normal,
QString &&style = "",
std::ostream &cout = std::cout) const;
/*! Write a string as note output. */
const InteractsWithIO &note(const QString &string, bool newline = true,
Verbosity verbosity = Normal) const;
/*! Write a string as information output. */
const InteractsWithIO &info(const QString &string, bool newline = true,
Verbosity verbosity = Normal) const;
/*! Write a string as error output. */
const InteractsWithIO &error(const QString &string, bool newline = true,
Verbosity verbosity = Normal) const;
/*! Write a string as comment output. */
const InteractsWithIO &comment(const QString &string, bool newline = true,
Verbosity verbosity = Normal) const;
/*! Write a string in an alert box. */
const InteractsWithIO &alert(const QString &string,
Verbosity verbosity = Normal) const;
/*! Write a string as error output (red box with a white text). */
const InteractsWithIO &errorWall(const QString &string,
Verbosity verbosity = Normal) const;
/*! Write a string as standard output, wide version. */
const InteractsWithIO &wline(const QString &string, bool newline = true,
Verbosity verbosity = Normal,
QString &&style = "",
std::wostream &wcout = std::wcout) const;
/*! Write a string as note output, wide version. */
const InteractsWithIO &wnote(const QString &string, bool newline = true,
Verbosity verbosity = Normal) const;
/*! Write a string as information output, wide version. */
const InteractsWithIO &winfo(const QString &string, bool newline = true,
Verbosity verbosity = Normal) const;
/*! Write a string as error output, wide version. */
const InteractsWithIO &werror(const QString &string, bool newline = true,
Verbosity verbosity = Normal) const;
/*! Write a string as comment output, wide version. */
const InteractsWithIO &wcomment(const QString &string, bool newline = true,
Verbosity verbosity = Normal) const;
/*! Write a string in an alert box, wide version. */
const InteractsWithIO &walert(const QString &string,
Verbosity verbosity = Normal) const;
/*! Write a string as error output (red box with a white text). */
const InteractsWithIO &werrorWall(const QString &string,
Verbosity verbosity = Normal) const;
/*! Write a blank line. */
const InteractsWithIO &newLine(int count = 1,
Verbosity verbosity = Normal) const;
/*! Write a blank line, wide version. */
const InteractsWithIO &newLineErr(int count = 1,
Verbosity verbosity = Normal) const;
/*! Format input to textual table. */
const InteractsWithIO &
table(const TableRow &headers, const std::vector<TableRow> &rows,
Verbosity verbosity = Normal) const;
/*! Confirm a question with the user. */
bool confirm(const QString &question, bool defaultAnswer = false) const;
protected:
/*! Default constructor (used by the TomApplication, instance is initialized
later in the TomApplication::parseCommandLine()). */
InteractsWithIO();
/*! Initialize instance like the second constructor do, allows to create
an instance in two steps. */
void initialize(const QCommandLineParser &parser);
/*! Get a current verbosity level. */
inline Verbosity verbosity() const noexcept;
/*! Is quiet verbosity level? */
inline bool isQuietVerbosity() const noexcept;
/*! Is normal verbosity level? */
inline bool isNormalVerbosity() const noexcept;
/*! Is verbose verbosity level? */
inline bool isVerboseVerbosity() const noexcept;
/*! Is very verbose verbosity level? */
inline bool isVeryVerboseVerbosity() const noexcept;
/*! Is debug verbosity level? */
inline bool isDebugVerbosity() const noexcept;
private:
/*! Constructor (used by TomApplication::logException()). */
explicit InteractsWithIO(bool noAnsi);
/*! Repalce text tags with ANSI sequences. */
QString parseOutput(QString string, bool isAnsi = true) const;
/*! Remove tom ansi tags from the given string. */
QString stripTags(QString string) const;
/*! Initialize verbosity by set options in the command-line parser. */
Verbosity initializeVerbosity(const QCommandLineParser &parser) const;
/*! Initialize ansi support by set options in the command-line parser. */
std::optional<bool> initializeAnsi(const QCommandLineParser &parser) const;
/*! Initialize ansi support by noAnsi passed to the Application::logException. */
std::optional<bool> initializeNoAnsi(bool noAnsi) const;
/*! Number of the option name set on the command line (used by eg. -vvv). */
QStringList::size_type
countSetOption(const QString &optionName, const QCommandLineParser &parser) const;
/*! Determine whether discard output by the current and the given verbosity. */
bool dontOutput(Verbosity verbosity) const;
/*! Should the given output use ansi? (ansi is disabled for non-tty). */
bool isAnsiOutput(std::ostream &cout = std::cout) const;
/*! Should the given output use ansi? (ansi is disabled for non-tty),
wide version. */
bool isAnsiWOutput(std::wostream &cout = std::wcout) const;
/*! Write a string as error output (red box with a white text). */
QString errorWallInternal(const QString &string) const;
/*! Alias for the tabulate color. */
using Color = tabulate::Color;
/*! Default tabulate table colors. */
struct TableColors
{
Color green = Color::green;
Color red = Color::red;
};
/*! Initialize tabulate table colors by supported ansi. */
TableColors initializeTableColors() const;
/*! Is this input means interactive? */
bool m_interactive = true;
/*! Current application verbosity (defined by passed command-line options). */
Verbosity m_verbosity = Normal;
/*! Current application ansi passed by command-line option. */
std::optional<bool> m_ansi = std::nullopt;
/*! Describes current terminal features. */
std::unique_ptr<Terminal> m_terminal;
};
/* protected */
InteractsWithIO::Verbosity InteractsWithIO::verbosity() const noexcept
{
return m_verbosity;
}
bool InteractsWithIO::isQuietVerbosity() const noexcept
{
return m_verbosity == Quiet;
}
bool InteractsWithIO::isNormalVerbosity() const noexcept
{
return m_verbosity == Normal;
}
bool InteractsWithIO::isVerboseVerbosity() const noexcept
{
return m_verbosity == Verbose;
}
bool InteractsWithIO::isVeryVerboseVerbosity() const noexcept
{
return m_verbosity == VeryVerbose;
}
bool InteractsWithIO::isDebugVerbosity() const noexcept
{
return m_verbosity == Debug;
}
} // namespace Concerns
} // namespace Tom
TINYORM_END_COMMON_NAMESPACE
#endif // TOM_CONCERNS_INTERACTSWITHIO_HPP
@@ -0,0 +1,53 @@
#pragma once
#ifndef TOM_CONCERNS_PRINTSOPTIONS_HPP
#define TOM_CONCERNS_PRINTSOPTIONS_HPP
#include <orm/macros/systemheader.hpp>
TINY_SYSTEM_HEADER
#include <QtGlobal>
#include <orm/macros/commonnamespace.hpp>
TINYORM_BEGIN_COMMON_NAMESPACE
namespace Tom
{
namespace Commands
{
class Command;
}
namespace Concerns
{
/*! Print options section. */
class PrintsOptions
{
Q_DISABLE_COPY(PrintsOptions)
public:
/*! Constructor (int param. to avoid interpret it as copy ctor). */
PrintsOptions(const Commands::Command &command, int);
/*! Default destructor. */
inline ~PrintsOptions() = default;
/*! Print options section. */
int printOptionsSection(bool commonOptions) const;
private:
/*! Get max. option size in all options. */
int optionsMaxSize() const;
/*! Print options to the console. */
void printOptions(int optionsMaxSize) const;
/*! Reference to the command. */
std::reference_wrapper<const Commands::Command> m_command;
};
} // namespace Concerns
} // namespace Tom
TINYORM_END_COMMON_NAMESPACE
#endif // TOM_CONCERNS_PRINTSOPTIONS_HPP
@@ -0,0 +1,26 @@
#pragma once
#ifndef TOM_EXCEPTIONS_INVALIDARGUMENTERROR_HPP
#define TOM_EXCEPTIONS_INVALIDARGUMENTERROR_HPP
#include <orm/macros/systemheader.hpp>
TINY_SYSTEM_HEADER
#include "tom/exceptions/logicerror.hpp"
TINYORM_BEGIN_COMMON_NAMESPACE
namespace Tom::Exceptions
{
/*! Tom Invalid argument exception. */
class InvalidArgumentError : public LogicError
{
/*! Inherit constructors. */
using LogicError::LogicError;
};
} // namespace Tom::Exceptions
TINYORM_END_COMMON_NAMESPACE
#endif // TOM_EXCEPTIONS_INVALIDARGUMENTERROR_HPP
@@ -0,0 +1,26 @@
#pragma once
#ifndef TOM_EXCEPTIONS_INVALIDTEMPLATEARGUMENTERROR_HPP
#define TOM_EXCEPTIONS_INVALIDTEMPLATEARGUMENTERROR_HPP
#include <orm/macros/systemheader.hpp>
TINY_SYSTEM_HEADER
#include "tom/exceptions/invalidargumenterror.hpp"
TINYORM_BEGIN_COMMON_NAMESPACE
namespace Tom::Exceptions
{
/*! Tom invalid template argument exception. */
class InvalidTemplateArgumentError : public InvalidArgumentError
{
/*! Inherit constructors. */
using InvalidArgumentError::InvalidArgumentError;
};
} // namespace Tom::Exceptions
TINYORM_END_COMMON_NAMESPACE
#endif // TOM_EXCEPTIONS_INVALIDTEMPLATEARGUMENTERROR_HPP
+48
View File
@@ -0,0 +1,48 @@
#pragma once
#ifndef TOM_EXCEPTIONS_LOGICERROR_HPP
#define TOM_EXCEPTIONS_LOGICERROR_HPP
#include <orm/macros/systemheader.hpp>
TINY_SYSTEM_HEADER
#include <QString>
#include <stdexcept>
#include "tom/exceptions/tomerror.hpp"
TINYORM_BEGIN_COMMON_NAMESPACE
namespace Tom::Exceptions
{
/*! Tom Logic exception. */
class LogicError : public std::logic_error,
public TomError
{
public:
/*! const char * constructor. */
explicit LogicError(const char *message);
/*! QString constructor. */
explicit LogicError(const QString &message);
/*! std::string constructor. */
explicit LogicError(const std::string &message);
/*! Return exception message as a QString. */
inline const QString &message() const noexcept;
protected:
/*! Exception message. */
QString m_message = what();
};
const QString &LogicError::message() const noexcept
{
return m_message;
}
} // namespace Tom::Exceptions
TINYORM_END_COMMON_NAMESPACE
#endif // TOM_EXCEPTIONS_LOGICERROR_HPP
@@ -0,0 +1,48 @@
#pragma once
#ifndef TOM_EXCEPTIONS_RUNTIMEERROR_HPP
#define TOM_EXCEPTIONS_RUNTIMEERROR_HPP
#include <orm/macros/systemheader.hpp>
TINY_SYSTEM_HEADER
#include <QString>
#include <stdexcept>
#include "tom/exceptions/tomerror.hpp"
TINYORM_BEGIN_COMMON_NAMESPACE
namespace Tom::Exceptions
{
/*! Tom Runtime exception. */
class RuntimeError : public std::runtime_error,
public TomError
{
public:
/*! const char * constructor. */
explicit RuntimeError(const char *message);
/*! QString constructor. */
explicit RuntimeError(const QString &message);
/*! std::string constructor. */
explicit RuntimeError(const std::string &message);
/*! Return exception message as a QString. */
inline const QString &message() const noexcept;
protected:
/*! Exception message. */
QString m_message = what();
};
const QString &RuntimeError::message() const noexcept
{
return m_message;
}
} // namespace Tom::Exceptions
TINYORM_END_COMMON_NAMESPACE
#endif // TOM_EXCEPTIONS_RUNTIMEERROR_HPP
+27
View File
@@ -0,0 +1,27 @@
#pragma once
#ifndef TOM_EXCEPTIONS_TOMERROR_HPP
#define TOM_EXCEPTIONS_TOMERROR_HPP
#include <orm/macros/systemheader.hpp>
TINY_SYSTEM_HEADER
#include <orm/macros/commonnamespace.hpp>
TINYORM_BEGIN_COMMON_NAMESPACE
namespace Tom::Exceptions
{
/*! Tom exceptions tag, all Tom exceptions are derived from this class. */
class TomError
{
public:
/*! Virtual destructor. */
inline virtual ~TomError() = default;
};
} // namespace Tom::Exceptions
TINYORM_END_COMMON_NAMESPACE
#endif // TOM_EXCEPTIONS_TOMERROR_HPP
+131
View File
@@ -0,0 +1,131 @@
#pragma once
#ifndef TOM_MIGRATION_HPP
#define TOM_MIGRATION_HPP
#include <orm/macros/systemheader.hpp>
TINY_SYSTEM_HEADER
#include <orm/schema.hpp>
TINYORM_BEGIN_COMMON_NAMESPACE
namespace Tom
{
/*! Migrations base class. */
class Migration
{
Q_DISABLE_COPY(Migration)
public:
/*! Default constructor. */
inline Migration() = default;
/*! Pure virtual destructor. */
inline virtual ~Migration() = 0;
/*! Run the migrations. */
virtual void up() const = 0;
/*! Reverse the migrations. */
virtual void down() const = 0;
/*! The name of the database connection to use. */
QString connection;
/*! Wrapping the migration within a transaction, if supported. */
bool withinTransaction = true;
};
Migration::~Migration() = default;
} // namespace Tom
TINYORM_END_COMMON_NAMESPACE
// Predefine some aliases so the user doesn't have to
namespace Migrations
{
/*! Alias for the Schema Blueprint. */
using TINYORM_COMMON_NAMESPACE::Orm::SchemaNs::Blueprint; // NOLINT(misc-unused-using-decls)
/*! Alias for the Tom Migration. */
using TINYORM_COMMON_NAMESPACE::Tom::Migration; // NOLINT(misc-unused-using-decls)
/*! Alias for the Orm Schema. */
using TINYORM_COMMON_NAMESPACE::Orm::Schema; // NOLINT(misc-unused-using-decls)
// Aliases for the most used string constants
/*! Alias for the string constant "id". */
using TINYORM_COMMON_NAMESPACE::Orm::Constants::ID; // NOLINT(misc-unused-using-decls)
/*! Alias for the string constant "name". */
using TINYORM_COMMON_NAMESPACE::Orm::Constants::NAME; // NOLINT(misc-unused-using-decls)
/*! Alias for the string constant "size". */
using TINYORM_COMMON_NAMESPACE::Orm::Constants::SIZE_; // NOLINT(misc-unused-using-decls)
/*! Alias for the string constant "created_at". */
using TINYORM_COMMON_NAMESPACE::Orm::Constants::CREATED_AT; // NOLINT(misc-unused-using-decls)
/*! Alias for the string constant "updated_at". */
using TINYORM_COMMON_NAMESPACE::Orm::Constants::UPDATED_AT; // NOLINT(misc-unused-using-decls)
/*! Alias for the string constant "MySQL". */
using TINYORM_COMMON_NAMESPACE::Orm::Constants::MYSQL_; // NOLINT(misc-unused-using-decls)
/*! Alias for the string constant "PostgreSQL". */
using TINYORM_COMMON_NAMESPACE::Orm::Constants::POSTGRESQL; // NOLINT(misc-unused-using-decls)
/*! Alias for the string constant "SQLite". */
using TINYORM_COMMON_NAMESPACE::Orm::Constants::SQLITE; // NOLINT(misc-unused-using-decls)
/*! Alias for the string constant "driver". */
using TINYORM_COMMON_NAMESPACE::Orm::Constants::driver_; // NOLINT(misc-unused-using-decls)
/*! Alias for the string constant "host". */
using TINYORM_COMMON_NAMESPACE::Orm::Constants::host_; // NOLINT(misc-unused-using-decls)
/*! Alias for the string constant "port". */
using TINYORM_COMMON_NAMESPACE::Orm::Constants::port_; // NOLINT(misc-unused-using-decls)
/*! Alias for the string constant "database". */
using TINYORM_COMMON_NAMESPACE::Orm::Constants::database_; // NOLINT(misc-unused-using-decls)
/*! Alias for the string constant "schema". */
using TINYORM_COMMON_NAMESPACE::Orm::Constants::schema_; // NOLINT(misc-unused-using-decls)
/*! Alias for the string constant "username". */
using TINYORM_COMMON_NAMESPACE::Orm::Constants::username_; // NOLINT(misc-unused-using-decls)
/*! Alias for the string constant "password". */
using TINYORM_COMMON_NAMESPACE::Orm::Constants::password_; // NOLINT(misc-unused-using-decls)
/*! Alias for the string constant "charset". */
using TINYORM_COMMON_NAMESPACE::Orm::Constants::charset_; // NOLINT(misc-unused-using-decls)
/*! Alias for the string constant "collation". */
using TINYORM_COMMON_NAMESPACE::Orm::Constants::collation_; // NOLINT(misc-unused-using-decls)
/*! Alias for the string constant "timezone". */
using TINYORM_COMMON_NAMESPACE::Orm::Constants::timezone_; // NOLINT(misc-unused-using-decls)
/*! Alias for the string constant "prefix". */
using TINYORM_COMMON_NAMESPACE::Orm::Constants::prefix_; // NOLINT(misc-unused-using-decls)
/*! Alias for the string constant "options". */
using TINYORM_COMMON_NAMESPACE::Orm::Constants::options_; // NOLINT(misc-unused-using-decls)
/*! Alias for the string constant "strict". */
using TINYORM_COMMON_NAMESPACE::Orm::Constants::strict_; // NOLINT(misc-unused-using-decls)
/*! Alias for the string constant "engine". */
using TINYORM_COMMON_NAMESPACE::Orm::Constants::engine_; // NOLINT(misc-unused-using-decls)
/*! Alias for the string constant "127.0.0.1". */
using TINYORM_COMMON_NAMESPACE::Orm::Constants::H127001; // NOLINT(misc-unused-using-decls)
/*! Alias for the string constant "localhost". */
using TINYORM_COMMON_NAMESPACE::Orm::Constants::LOCALHOST; // NOLINT(misc-unused-using-decls)
/*! Alias for the string constant "3306". */
using TINYORM_COMMON_NAMESPACE::Orm::Constants::P3306; // NOLINT(misc-unused-using-decls)
/*! Alias for the string constant "5432". */
using TINYORM_COMMON_NAMESPACE::Orm::Constants::P5432; // NOLINT(misc-unused-using-decls)
/*! Alias for the string constant "root". */
using TINYORM_COMMON_NAMESPACE::Orm::Constants::ROOT; // NOLINT(misc-unused-using-decls)
/*! Alias for the string constant "UTC". */
using TINYORM_COMMON_NAMESPACE::Orm::Constants::UTC; // NOLINT(misc-unused-using-decls)
/*! Alias for the string constant "LOCAL". */
using TINYORM_COMMON_NAMESPACE::Orm::Constants::LOCAL; // NOLINT(misc-unused-using-decls)
/*! Alias for the string constant "SYSTEM". */
using TINYORM_COMMON_NAMESPACE::Orm::Constants::SYSTEM; // NOLINT(misc-unused-using-decls)
/*! Alias for the string constant "public". */
using TINYORM_COMMON_NAMESPACE::Orm::Constants::PUBLIC; // NOLINT(misc-unused-using-decls)
/*! Alias for the string constant "utf8". */
using TINYORM_COMMON_NAMESPACE::Orm::Constants::UTF8; // NOLINT(misc-unused-using-decls)
/*! Alias for the string constant "utf8mb4". */
using TINYORM_COMMON_NAMESPACE::Orm::Constants::UTF8MB4; // NOLINT(misc-unused-using-decls)
/*! Alias for the string constant "InnoDB". */
using TINYORM_COMMON_NAMESPACE::Orm::Constants::InnoDB; // NOLINT(misc-unused-using-decls)
/*! Alias for the string constant "MyISAM". */
using TINYORM_COMMON_NAMESPACE::Orm::Constants::MyISAM; // NOLINT(misc-unused-using-decls)
} // namespace Migrations
#endif // TOM_MIGRATION_HPP
+65
View File
@@ -0,0 +1,65 @@
#pragma once
#ifndef TOM_MIGRATIONCREATOR_HPP
#define TOM_MIGRATIONCREATOR_HPP
#include <orm/macros/systemheader.hpp>
TINY_SYSTEM_HEADER
#include <QString>
#include <filesystem>
#include <orm/macros/commonnamespace.hpp>
TINYORM_BEGIN_COMMON_NAMESPACE
namespace Tom
{
/*! Migration file generator (used by the make:migration command). */
class MigrationCreator
{
Q_DISABLE_COPY(MigrationCreator)
/*! Alias for the filesystem path. */
using fspath = std::filesystem::path;
public:
/*! Default constructor. */
inline MigrationCreator() = default;
/*! Default destructor. */
inline ~MigrationCreator() = default;
/*! Create a new migration at the given path. */
fspath create(const QString &name, fspath &&migrationsPath,
const QString &table = "", bool create = false) const;
protected:
/*! Ensure that a migration with the given name doesn't already exist. */
void throwIfMigrationAlreadyExists(const QString &name,
const fspath &migrationsPath) const;
/*! Get the migration stub file. */
QString getStub(const QString &table, bool create) const;
/*! Get the path to the stubs. */
fspath stubPath() const;
/*! Get the full path to the migration. */
fspath getPath(const QString &name, const fspath &path) const;
/*! Get the date prefix for the migration. */
std::string getDatePrefix() const;
/*! Populate the place-holders in the migration stub. */
std::string populateStub(const QString &name, QString &&stub,
const QString &table) const;
/*! Get the class name of a migration name. */
QString getClassName(const QString &name) const;
/*! Ensure a directory exists. */
void ensureDirectoryExists(fspath &&path) const;
};
} // namespace Tom
TINYORM_END_COMMON_NAMESPACE
#endif // TOM_MIGRATIONCREATOR_HPP
+94
View File
@@ -0,0 +1,94 @@
#pragma once
#ifndef TOM_MIGRATIONREPOSITORY_HPP
#define TOM_MIGRATIONREPOSITORY_HPP
#include <QSharedPointer>
#include <orm/connectionresolverinterface.hpp>
#include "tom/tomtypes.hpp"
class QSqlQuery;
TINYORM_BEGIN_COMMON_NAMESPACE
namespace Orm::Query
{
class Builder;
}
namespace Tom
{
/*! Migrations database repository. */
class MigrationRepository
{
Q_DISABLE_COPY(MigrationRepository)
/*! Alias for the ConnectionResolverInterface. */
using ConnectionResolverInterface = Orm::ConnectionResolverInterface;
/*! Alias for the DatabaseConnection. */
using DatabaseConnection = Orm::DatabaseConnection;
/*! Alias for the QueryBuilder. */
using QueryBuilder = Orm::Query::Builder;
public:
/*! Constructor. */
MigrationRepository(std::shared_ptr<ConnectionResolverInterface> &&resolver,
QString table);
/*! Default destructor. */
inline ~MigrationRepository() = default;
/*! Get the completed migrations (only migration names using pluck). */
QVector<QVariant> getRanSimple() const;
/*! Get the completed migrations. */
std::vector<MigrationItem> getRan(const QString &order) const;
/*! Get list of migrations. */
std::vector<MigrationItem> getMigrations(int steps) const;
/*! Get the last migration batch. */
std::vector<MigrationItem> getLast() const;
/*! Get the completed migrations with their batch numbers. */
std::map<QString, QVariant> getMigrationBatches() const;
/*! Log that a migration was run. */
void log(const QString &file, int batch) const;
/*! Remove a migration from the log. */
void deleteMigration(quint64 id) const;
/*! Get the next migration batch number. */
int getNextBatchNumber() const;
/*! Get the last migration batch number. */
int getLastBatchNumber() const;
/*! Create the migration repository data store. */
void createRepository() const;
/*! Determine if the migration repository exists. */
bool repositoryExists() const;
/*! Delete the migration repository data store. */
void deleteRepository() const;
/*! Resolve the database connection instance. */
DatabaseConnection &getConnection() const;
/*! Set the connection name to use in the repository. */
void setConnection(const QString &name, std::optional<bool> &&debugSql);
protected:
/*! Get a query builder for the migration table. */
QSharedPointer<QueryBuilder> table() const;
/*! Hydrate a vector of migration items from a raw QSqlQuery. */
std::vector<MigrationItem> hydrateMigrations(QSqlQuery &query) const;
/*! Set the debug sql for the current repository connection. */
void setConnectionDebugSql(std::optional<bool> &&debugSql) const;
/*! The database connection resolver instance. */
std::shared_ptr<ConnectionResolverInterface> m_resolver;
/*! The name of the migration table. */
QString m_table;
/*! The name of the database connection to use. */
QString m_connection {};
};
} // namespace Tom
TINYORM_END_COMMON_NAMESPACE
#endif // TOM_MIGRATIONREPOSITORY_HPP
+178
View File
@@ -0,0 +1,178 @@
#pragma once
#ifndef TOM_MIGRATOR_HPP
#define TOM_MIGRATOR_HPP
#include <set>
#include <typeindex>
#include <orm/connectionresolverinterface.hpp>
#include <orm/types/log.hpp>
#include "tom/concerns/interactswithio.hpp"
#include "tom/tomtypes.hpp"
TINYORM_BEGIN_COMMON_NAMESPACE
namespace Tom
{
class MigrationRepository;
/*! Migration service class. */
class Migrator : public Concerns::InteractsWithIO
{
Q_DISABLE_COPY(Migrator)
/*! Alias for the ConnectionResolverInterface. */
using ConnectionResolverInterface = Orm::ConnectionResolverInterface;
/*! Alias for the DatabaseConnection. */
using DatabaseConnection = Orm::DatabaseConnection;
/*! Alias for the pretend Log. */
using Log = Orm::Types::Log;
public:
/*! Constructor. */
Migrator(std::shared_ptr<MigrationRepository> &&repository,
std::shared_ptr<ConnectionResolverInterface> &&resolver,
const std::vector<std::shared_ptr<Migration>> &migrations,
const QCommandLineParser &parser);
/*! Default destructor. */
inline ~Migrator() = default;
/* Main migrate operations */
/*! Migrate options. */
struct MigrateOptions
{
/*! Dump the SQL queries that would be run. */
bool pretend = false;
/*! Force the migrations to be run so they can be rolled back individually. */
bool step = false;
/*! The number of migrations to be reverted. */
int stepValue = 0;
};
/*! Run the pending migrations. */
std::vector<std::shared_ptr<Migration>> run(MigrateOptions options) const;
/*! Rollback the last migration operation. */
std::vector<RollbackItem> rollback(MigrateOptions options) const;
/*! Rolls all of the currently applied migrations back. */
std::vector<RollbackItem> reset(bool pretend = false) const;
/* Database connection related */
/*! Execute the given callback using the given connection as the default
connection. */
int usingConnection(QString &&name, bool debugSql,
std::function<int()> &&callback);
/* Proxies to MigrationRepository */
/*! Determine if the migration repository exists. */
bool repositoryExists() const;
/*! Determine if any migrations have been run. */
bool hasRunAnyMigrations() const;
/* Getters / Setters */
/*! Get the default connection name. */
inline const QString &getConnection() const noexcept;
/*! Set the default connection name. */
void setConnection(QString &&name, std::optional<bool> &&debugSql);
/*! Get the migration repository instance. */
inline MigrationRepository &repository() const noexcept;
/*! Get migration names list. */
inline const std::set<QString> &migrationNames() const noexcept;
protected:
/* Database connection related */
/*! Resolve the database connection instance. */
DatabaseConnection &resolveConnection(const QString &name = "") const;
/*! Get the debug sql by the connection name. */
std::optional<bool> getConnectionDebugSql(const QString &name) const;
/* Migration instances lists and hashes */
/*! Create a map that maps migration names by migrations type-id (type_index). */
void createMigrationNamesMap();
/*! Get a migration name by a migration type-id. */
QString getMigrationName(const Migration &migration) const;
/* Migrate */
/*! Get the migration instances that have not yet run. */
std::vector<std::shared_ptr<Migration>>
pendingMigrations(const QVector<QVariant> &ran) const;
/*! Run "up" a migration instance. */
void runUp(const Migration &migration, int batch, bool pretend) const;
/* Rollback */
/*! Get the migrations for a rollback operation (used by rollback). */
std::vector<RollbackItem>
getMigrationsForRollback(MigrateOptions options) const;
/*! Get the migrations for a rollback operation (used by reset). */
std::vector<RollbackItem>
getMigrationsForRollback(std::vector<MigrationItem> &&ran) const;
/*! Rollback the given migrations. */
std::vector<RollbackItem>
rollbackMigrations(std::vector<RollbackItem> &&migrations, bool pretend) const;
/*! Run "down" a migration instance. */
void runDown(const RollbackItem &migrationToRollback, bool pretend) const;
/* Pretend */
/*! Migrate type (up/down). */
enum struct MigrateMethod { Up, Down };
/*! Pretend to run the migrations. */
void pretendToRun(const Migration &migration, MigrateMethod method) const;
/*! Get all of the queries that would be run for a migration. */
QVector<Log> getQueries(const Migration &migration, MigrateMethod method) const;
/* Migrate up/down common */
/*! Run a migration inside a transaction if the database supports it. */
void runMigration(const Migration &migration, MigrateMethod method) const;
/*! Migrate by the given method (up/down). */
void migrateByMethod(const Migration &migration, MigrateMethod method) const;
/*! Throw if migrations passed to the TomApplication are not sorted
alphabetically. */
void throwIfMigrationsNotSorted(const QString &previousMigrationName,
const QString &migrationName) const;
/*! The migration repository instance. */
std::shared_ptr<MigrationRepository> m_repository;
/*! The database connection resolver instance. */
std::shared_ptr<ConnectionResolverInterface> m_resolver;
/*! The name of the database connection to use. */
QString m_connection;
/*! Reference to the migrations vector to process. */
const std::vector<std::shared_ptr<Migration>> &m_migrations;
/*! Map a migration names by migrations type-id (type_index)
(used migrate, rollback, pretend). */
std::unordered_map<std::type_index, QString> m_migrationNamesMap {};
/*! Migration names list (used by status). */
std::set<QString> m_migrationNames {};
/*! Map a migration instances by migration names (used by reset). */
std::unordered_map<QString,
std::shared_ptr<Migration>> m_migrationInstancesMap {};
};
/* public */
const QString &Migrator::getConnection() const noexcept
{
return m_connection;
}
MigrationRepository &Migrator::repository() const noexcept
{
return *m_repository;
}
const std::set<QString> &Migrator::migrationNames() const noexcept
{
return m_migrationNames;
}
} // namespace Tom
TINYORM_END_COMMON_NAMESPACE
#endif // TOM_MIGRATOR_HPP
+129
View File
@@ -0,0 +1,129 @@
#pragma once
#ifndef TOM_TERMINAL_HPP
#define TOM_TERMINAL_HPP
#include <orm/macros/systemheader.hpp>
TINY_SYSTEM_HEADER
#include <QString>
#include <iostream>
#include <orm/macros/commonnamespace.hpp>
TINYORM_BEGIN_COMMON_NAMESPACE
namespace Tom
{
/*! Concept for the ostream and wostream. */
template<typename T>
concept OStreamConcept = std::convertible_to<T, const std::ostream &> ||
std::convertible_to<T, const std::wostream &>;
/*! Describes current terminal features. */
class Terminal
{
Q_DISABLE_COPY(Terminal)
public:
/*! Default constructor. */
inline Terminal() = default;
/*! Default destructor. */
inline ~Terminal() = default;
/*! Supports the given output ansi colors? (ansi is disabled for non-tty). */
bool hasColorSupport(std::ostream &cout = std::cout) const;
/*! Supports the given output ansi colors? (ansi is disabled for non-tty),
wide version. */
bool hasWColorSupport(std::wostream &wcout = std::wcout) const;
/*! Determines whether a file descriptor is associated with a character device. */
bool isatty(FILE *stream) const;
/*! Obtain the current terminal width. */
int width();
/*! Obtain the current terminal height. */
int height();
/*! Get the cached terminal width. */
inline int lastWidth() const noexcept;
/*! Get the cached terminal height. */
inline int lastHeight() const noexcept;
/*! Terminal width and height. */
struct TerminalSize
{
/*! Visible columns. */
int columns;
/*! Visible lines. */
int lines;
};
/*! Get terminal size of the visible area. */
TerminalSize terminalSize() const;
private:
/*! Supports the given output ansi colors? (common logic). */
template<OStreamConcept O>
bool hasColorSupportInternal(O &&cout, FILE *stream) const;
#ifdef _WIN32
/*! Detect if c++ ostream has enabled virtual terminal processing. */
bool hasVt100Support(std::ostream &cout) const;
/*! Detect if c++ wostream has enabled virtual terminal processing,
wide version. */
bool hasVt100Support(std::wostream &wcout) const;
#endif
/*! Cache for detected ansi output. */
mutable std::unordered_map<std::ostream *, bool> m_isAnsiOutput;
/*! Cache for detected ansi output, wide version. */
mutable std::unordered_map<std::wostream *, bool> m_isAnsiWOutput;
/*! Current terminal width. */
int m_lastWidth = 80;
/*! Current terminal height. */
int m_lastHeight = 50;
};
/* public */
int Terminal::lastWidth() const noexcept
{
return m_lastWidth;
}
int Terminal::lastHeight() const noexcept
{
return m_lastHeight;
}
/* private */
template<OStreamConcept O>
bool Terminal::hasColorSupportInternal(O &&cout, FILE *stream) const
{
// Follow https://no-color.org/
if (qEnvironmentVariableIsSet("NO_COLOR"))
return false;
if (qEnvironmentVariable("TERM_PROGRAM") == QLatin1String("Hyper"))
return isatty(stream);
#ifdef _WIN32
return isatty(stream) &&
(hasVt100Support(std::forward<O>(cout)) ||
qEnvironmentVariableIsSet("ANSICON") ||
qEnvironmentVariable("ConEmuANSI") == QLatin1String("ON") ||
qEnvironmentVariable("TERM") == QLatin1String("xterm"));
#endif
// Detect character device, in most cases false when the output is redirected
return isatty(stream);
}
} // namespace Tom
TINYORM_END_COMMON_NAMESPACE
#endif // TOM_TERMINAL_HPP
+46
View File
@@ -0,0 +1,46 @@
#pragma once
#ifndef TOM_TOMTYPES_HPP
#define TOM_TOMTYPES_HPP
#include <orm/macros/systemheader.hpp>
TINY_SYSTEM_HEADER
#include <QString>
#include <memory>
#include <orm/macros/commonnamespace.hpp>
TINYORM_BEGIN_COMMON_NAMESPACE
namespace Tom
{
/*! Hydrated migration item from the database. */
struct MigrationItem
{
/*! Database ID. */
quint64 id;
/*! Migration name. */
QString migration;
int batch;
};
class Migration;
/*! Migration item used and returned from the rollback. */
struct RollbackItem
{
/*! Database ID. */
quint64 id;
/*! Migration name. */
QString migrationName;
/*! Migration instance. */
std::shared_ptr<Migration> migration;
};
} // namespace Tom
TINYORM_END_COMMON_NAMESPACE
#endif // TOM_TOMTYPES_HPP