mirror of
https://github.com/silverqx/TinyORM.git
synced 2025-12-21 10:29:36 -06:00
tom added force option to make commands
Allow to overwrite already existing migration, model, seeder.
This commit is contained in:
@@ -266,6 +266,7 @@ function(tinytom_sources out_headers out_sources)
|
||||
commands/integratecommand.hpp
|
||||
commands/listcommand.hpp
|
||||
commands/make/concerns/prepareoptionvalues.hpp
|
||||
commands/make/makecommand.hpp
|
||||
commands/make/migrationcommand.hpp
|
||||
commands/make/modelcommand.hpp
|
||||
commands/make/modelcommandconcepts.hpp
|
||||
@@ -334,6 +335,7 @@ function(tinytom_sources out_headers out_sources)
|
||||
commands/integratecommand.cpp
|
||||
commands/listcommand.cpp
|
||||
commands/make/concerns/prepareoptionvalues.cpp
|
||||
commands/make/makecommand.cpp
|
||||
commands/make/migrationcommand.cpp
|
||||
commands/make/modelcommand.cpp
|
||||
# commands/make/projectcommand.cpp
|
||||
|
||||
@@ -19,6 +19,7 @@ headersList += \
|
||||
$$PWD/tom/commands/integratecommand.hpp \
|
||||
$$PWD/tom/commands/listcommand.hpp \
|
||||
$$PWD/tom/commands/make/concerns/prepareoptionvalues.hpp \
|
||||
$$PWD/tom/commands/make/makecommand.hpp \
|
||||
$$PWD/tom/commands/make/migrationcommand.hpp \
|
||||
$$PWD/tom/commands/make/modelcommand.hpp \
|
||||
$$PWD/tom/commands/make/modelcommandconcepts.hpp \
|
||||
|
||||
56
tom/include/tom/commands/make/makecommand.hpp
Normal file
56
tom/include/tom/commands/make/makecommand.hpp
Normal file
@@ -0,0 +1,56 @@
|
||||
#pragma once
|
||||
#ifndef TOM_COMMANDS_MAKE_MAKECOMMAND_HPP
|
||||
#define TOM_COMMANDS_MAKE_MAKECOMMAND_HPP
|
||||
|
||||
#include <orm/macros/systemheader.hpp>
|
||||
TINY_SYSTEM_HEADER
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
#include "tom/commands/command.hpp"
|
||||
|
||||
TINYORM_BEGIN_COMMON_NAMESPACE
|
||||
|
||||
namespace Tom::Commands::Make
|
||||
{
|
||||
|
||||
/*! Base class for the make-related commands. */
|
||||
class MakeCommand : public Command
|
||||
{
|
||||
Q_DISABLE_COPY(MakeCommand)
|
||||
|
||||
/*! Alias for the filesystem path. */
|
||||
using fspath = std::filesystem::path;
|
||||
|
||||
public:
|
||||
/*! Constructor. */
|
||||
MakeCommand(Application &application, QCommandLineParser &parser);
|
||||
/*! Virtual destructor. */
|
||||
inline ~MakeCommand() override = default;
|
||||
|
||||
protected:
|
||||
/*! Check whether the created file already exists and create folder if needed. */
|
||||
void prepareFileSystem(
|
||||
const QString &type, const fspath &folder, const QString &basename,
|
||||
const QString &className = {}) const;
|
||||
|
||||
/*! Throw if the given classname constains a namespace or path. */
|
||||
static void throwIfContainsNamespaceOrPath(
|
||||
const QString &type, const QString &className,
|
||||
const QString &source);
|
||||
|
||||
private:
|
||||
/*! Ensure that a file in the given folder doesn't already exist. */
|
||||
void throwIfModelAlreadyExists(
|
||||
const QString &type, const fspath &folder, const QString &basename,
|
||||
const QString &className) const;
|
||||
|
||||
/*! Ensure a directory exists. */
|
||||
static void ensureDirectoryExists(const fspath &path);
|
||||
};
|
||||
|
||||
} // namespace Tom::Commands::Make
|
||||
|
||||
TINYORM_END_COMMON_NAMESPACE
|
||||
|
||||
#endif // TOM_COMMANDS_MAKE_MAKECOMMAND_HPP
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <orm/macros/systemheader.hpp>
|
||||
TINY_SYSTEM_HEADER
|
||||
|
||||
#include "tom/commands/command.hpp"
|
||||
#include "tom/commands/make/makecommand.hpp"
|
||||
#include "tom/commands/make/support/migrationcreator.hpp"
|
||||
#include "tom/tomconstants.hpp"
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Tom::Commands::Make
|
||||
{
|
||||
|
||||
/*! Create a new migration file. */
|
||||
class MigrationCommand : public Command
|
||||
class MigrationCommand : public MakeCommand
|
||||
{
|
||||
Q_DISABLE_COPY(MigrationCommand)
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@ TINY_SYSTEM_HEADER
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
#include "tom/commands/command.hpp"
|
||||
#include "tom/commands/make/concerns/prepareoptionvalues.hpp"
|
||||
#include "tom/commands/make/makecommand.hpp"
|
||||
#include "tom/commands/make/modelcommandconcepts.hpp"
|
||||
#include "tom/commands/make/support/modelcreator.hpp"
|
||||
#include "tom/tomconstants.hpp"
|
||||
@@ -28,7 +28,7 @@ namespace Support
|
||||
} // namespace Support
|
||||
|
||||
/*! Create a new model class. */
|
||||
class ModelCommand : public Command,
|
||||
class ModelCommand : public MakeCommand,
|
||||
protected Concerns::PrepareOptionValues
|
||||
{
|
||||
Q_DISABLE_COPY(ModelCommand)
|
||||
@@ -121,13 +121,12 @@ namespace Support
|
||||
private:
|
||||
/*! Throw if the model name constains a namespace or path. */
|
||||
static void throwIfContainsNamespaceOrPath(
|
||||
const std::vector<QStringList> &classNames, const QString &source);
|
||||
const std::vector<QStringList> &classNames, const QString &source,
|
||||
const QString &commandType = QStringLiteral("model"));
|
||||
/*! Throw if the model name constains a namespace or path. */
|
||||
static void throwIfContainsNamespaceOrPath(const QStringList &classNames,
|
||||
const QString &source);
|
||||
/*! Throw if the model name constains a namespace or path. */
|
||||
static void throwIfContainsNamespaceOrPath(const QString &className,
|
||||
const QString &source);
|
||||
static void throwIfContainsNamespaceOrPath(
|
||||
const QStringList &classNames, const QString &source,
|
||||
const QString &commandType = QStringLiteral("model"));
|
||||
};
|
||||
|
||||
/* public */
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <orm/macros/systemheader.hpp>
|
||||
TINY_SYSTEM_HEADER
|
||||
|
||||
#include "tom/commands/command.hpp"
|
||||
#include "tom/commands/make/makecommand.hpp"
|
||||
#include "tom/commands/make/support/seedercreator.hpp"
|
||||
#include "tom/tomconstants.hpp"
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Tom::Commands::Make
|
||||
{
|
||||
|
||||
/*! Create a new seeder class. */
|
||||
class SeederCommand : public Command
|
||||
class SeederCommand : public MakeCommand
|
||||
{
|
||||
Q_DISABLE_COPY(SeederCommand)
|
||||
|
||||
@@ -54,10 +54,6 @@ namespace Tom::Commands::Make
|
||||
|
||||
/*! The seeder creator instance. */
|
||||
Support::SeederCreator m_creator {};
|
||||
|
||||
private:
|
||||
/*! Throw if the seeder name constains a namespace or path. */
|
||||
static void throwIfContainsNamespaceOrPath(const QString &className);
|
||||
};
|
||||
|
||||
/* public */
|
||||
|
||||
@@ -50,13 +50,6 @@ namespace Tom::Commands::Make::Support
|
||||
populateStub(const QString &name, QString &&stub, const QString &table);
|
||||
/*! Get the class name of a migration name. */
|
||||
static QString getClassName(const QString &name);
|
||||
/*! Ensure a directory exists. */
|
||||
static void ensureDirectoryExists(const fspath &path);
|
||||
|
||||
private:
|
||||
/*! Ensure that a migration with the given name doesn't already exist. */
|
||||
static void throwIfMigrationAlreadyExists(const QString &name,
|
||||
const fspath &migrationsPath);
|
||||
};
|
||||
|
||||
} // namespace Tom::Commands::Make::Support
|
||||
|
||||
@@ -41,9 +41,6 @@ namespace Tom::Commands::Make::Support
|
||||
/*! Get the full path to the model. */
|
||||
static fspath getPath(const QString &basename, const fspath &path);
|
||||
|
||||
/*! Ensure a directory exists. */
|
||||
static void ensureDirectoryExists(const fspath &path);
|
||||
|
||||
/*! Populate the place-holders in the model stub. */
|
||||
std::string populateStub(const QString &className, const CmdOptions &cmdOptions,
|
||||
bool isSetPreserveOrder);
|
||||
@@ -192,12 +189,6 @@ namespace Tom::Commands::Make::Support
|
||||
|
||||
/*! Cached relations list size to avoid recomputation. */
|
||||
std::size_t m_relationsListSize = 0;
|
||||
|
||||
private:
|
||||
/*! Ensure that a model with the given name doesn't already exist. */
|
||||
static void throwIfModelAlreadyExists(
|
||||
const QString &className, const QString &basename,
|
||||
const fspath &modelsPath);
|
||||
};
|
||||
|
||||
} // namespace Tom::Commands::Make::Support
|
||||
|
||||
@@ -37,21 +37,12 @@ namespace Tom::Commands::Make::Support
|
||||
/*! Get the full path to the seeder. */
|
||||
static fspath getPath(const QString &basename, const fspath &path);
|
||||
|
||||
/*! Ensure a directory exists. */
|
||||
static void ensureDirectoryExists(const fspath &path);
|
||||
|
||||
/*! Populate the place-holders in the seeder stub. */
|
||||
static std::string
|
||||
populateStub(const QString &className, QString &&table);
|
||||
|
||||
/*! Get the table name from the seeder class name. */
|
||||
static QString getTableName(QString className);
|
||||
|
||||
private:
|
||||
/*! Ensure that a seeder with the given name doesn't already exist. */
|
||||
void throwIfSeederAlreadyExists(
|
||||
const QString &className, const QString &basename,
|
||||
const fspath &seedersPath) const;
|
||||
};
|
||||
|
||||
} // namespace Tom::Commands::Make::Support
|
||||
|
||||
@@ -14,6 +14,7 @@ sourcesList += \
|
||||
$$PWD/tom/commands/integratecommand.cpp \
|
||||
$$PWD/tom/commands/listcommand.cpp \
|
||||
$$PWD/tom/commands/make/concerns/prepareoptionvalues.cpp \
|
||||
$$PWD/tom/commands/make/makecommand.cpp \
|
||||
$$PWD/tom/commands/make/migrationcommand.cpp \
|
||||
$$PWD/tom/commands/make/modelcommand.cpp \
|
||||
# $$PWD/tom/commands/make/projectcommand.cpp \
|
||||
|
||||
100
tom/src/tom/commands/make/makecommand.cpp
Normal file
100
tom/src/tom/commands/make/makecommand.cpp
Normal file
@@ -0,0 +1,100 @@
|
||||
#include "tom/commands/make/makecommand.hpp"
|
||||
|
||||
#include "tom/exceptions/invalidargumenterror.hpp"
|
||||
#include "tom/tomconstants.hpp"
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
using fspath = std::filesystem::path;
|
||||
|
||||
using Tom::Constants::DateTimePrefix;
|
||||
using Tom::Constants::force;
|
||||
|
||||
TINYORM_BEGIN_COMMON_NAMESPACE
|
||||
|
||||
namespace Tom::Commands::Make
|
||||
{
|
||||
|
||||
/* public */
|
||||
|
||||
MakeCommand::MakeCommand(Application &application, QCommandLineParser &parser)
|
||||
: Command(application, parser)
|
||||
{}
|
||||
|
||||
/* protected */
|
||||
|
||||
void MakeCommand::prepareFileSystem(
|
||||
const QString &type, const fspath &folder, const QString &basename,
|
||||
const QString &className) const
|
||||
{
|
||||
throwIfModelAlreadyExists(type, folder, basename, className);
|
||||
|
||||
ensureDirectoryExists(folder);
|
||||
}
|
||||
|
||||
void MakeCommand::throwIfContainsNamespaceOrPath(
|
||||
const QString &type, const QString &className, const QString &source)
|
||||
{
|
||||
if (!className.contains(QStringLiteral("::")) && !className.contains(QChar('/')) &&
|
||||
!className.contains(QChar('\\'))
|
||||
)
|
||||
return;
|
||||
|
||||
throw Exceptions::InvalidArgumentError(
|
||||
QStringLiteral("Namespace or path is not allowed in the %1 name (%2).")
|
||||
.arg(type, source));
|
||||
}
|
||||
|
||||
/* private */
|
||||
|
||||
void MakeCommand::throwIfModelAlreadyExists(
|
||||
const QString &type, const fspath &folder, const QString &basename,
|
||||
const QString &className) const
|
||||
{
|
||||
// Nothing to check
|
||||
if (!fs::exists(folder))
|
||||
return;
|
||||
|
||||
auto itemName = className.isEmpty() ? basename : className;
|
||||
|
||||
using options = fs::directory_options;
|
||||
|
||||
for (const auto &entry :
|
||||
fs::directory_iterator(folder, options::skip_permission_denied)
|
||||
) {
|
||||
// Check only files
|
||||
if (!entry.is_regular_file())
|
||||
continue;
|
||||
|
||||
// Extract base filename without the extension
|
||||
auto entryName = QString::fromStdString(entry.path().stem().string());
|
||||
|
||||
// If checking a migration then also remove the datetime prefix
|
||||
if (type == QStringLiteral("migration"))
|
||||
entryName = entryName.mid(DateTimePrefix.size() + 1);
|
||||
|
||||
if (entryName == basename) {
|
||||
// Allow overwriting a file using the --force option
|
||||
if (!isSet(force))
|
||||
throw Exceptions::InvalidArgumentError(
|
||||
QStringLiteral("A '%1' %2 already exists.")
|
||||
.arg(std::move(itemName), type));
|
||||
|
||||
comment(QStringLiteral("Overwriting '%1' already existing %2.")
|
||||
.arg(std::move(itemName), type));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MakeCommand::ensureDirectoryExists(const fspath &path)
|
||||
{
|
||||
if (fs::exists(path) && fs::is_directory(path))
|
||||
return;
|
||||
|
||||
fs::create_directories(path);
|
||||
}
|
||||
|
||||
} // namespace Tom::Commands::Make
|
||||
|
||||
TINYORM_END_COMMON_NAMESPACE
|
||||
@@ -23,6 +23,7 @@ using StringUtils = Orm::Tiny::Utils::String;
|
||||
|
||||
using Tom::Constants::create_;
|
||||
using Tom::Constants::create_up;
|
||||
using Tom::Constants::force;
|
||||
using Tom::Constants::fullpath;
|
||||
using Tom::Constants::path_;
|
||||
using Tom::Constants::path_up;
|
||||
@@ -41,7 +42,7 @@ namespace Tom::Commands::Make
|
||||
/* public */
|
||||
|
||||
MigrationCommand::MigrationCommand(Application &application, QCommandLineParser &parser)
|
||||
: Command(application, parser)
|
||||
: MakeCommand(application, parser)
|
||||
{}
|
||||
|
||||
const std::vector<PositionalArgument> &MigrationCommand::positionalArguments() const
|
||||
@@ -56,13 +57,16 @@ const std::vector<PositionalArgument> &MigrationCommand::positionalArguments() c
|
||||
QList<QCommandLineOption> MigrationCommand::optionsSignature() const
|
||||
{
|
||||
return {
|
||||
{create_, QStringLiteral("The table name to be created"), create_up}, // Value
|
||||
{table_, QStringLiteral("The table name to migrate (update)"), table_up}, // Value
|
||||
{path_, QStringLiteral("The location where the migration file should be "
|
||||
"created"), path_up}, // Value
|
||||
{realpath_, QStringLiteral("Indicate that any provided migration file paths are "
|
||||
"pre-resolved absolute paths")},
|
||||
{fullpath, QStringLiteral("Output the full path of the created migration")},
|
||||
{create_, QStringLiteral("The table name to be created"), create_up}, // Value
|
||||
{table_, QStringLiteral("The table name to migrate (update)"), table_up}, // Value
|
||||
{path_, QStringLiteral("The location where the migration file should be "
|
||||
"created"), path_up}, // Value
|
||||
{realpath_, QStringLiteral("Indicate that any provided migration file paths "
|
||||
"are pre-resolved absolute paths")},
|
||||
{fullpath, QStringLiteral("Output the full path of the created migration")},
|
||||
|
||||
{{QChar('f'),
|
||||
force}, QStringLiteral("Overwrite the migration file if already exists")},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -76,6 +80,9 @@ int MigrationCommand::run()
|
||||
auto [datetimePrefix, migrationName, extension] =
|
||||
prepareMigrationNameClassName(argument(NAME).trimmed());
|
||||
|
||||
// Check whether a migration file already exists and create parent folder if needed
|
||||
prepareFileSystem(QStringLiteral("migration"), getMigrationPath(), migrationName);
|
||||
|
||||
auto table = value(table_);
|
||||
|
||||
auto createArg = value(create_);
|
||||
@@ -206,6 +213,11 @@ void MigrationCommand::writeMigration(
|
||||
|
||||
fspath MigrationCommand::getMigrationPath() const
|
||||
{
|
||||
static fspath cached;
|
||||
|
||||
if (!cached.empty())
|
||||
return cached;
|
||||
|
||||
// Default location
|
||||
if (!isSet(path_))
|
||||
return application().getMigrationsPath();
|
||||
@@ -225,7 +237,7 @@ fspath MigrationCommand::getMigrationPath() const
|
||||
QStringLiteral("Migrations path '%1' exists and it's not a directory.")
|
||||
.arg(migrationsPath.c_str()));
|
||||
|
||||
return migrationsPath;
|
||||
return cached = migrationsPath;
|
||||
}
|
||||
|
||||
} // namespace Tom::Commands::Make
|
||||
|
||||
@@ -41,6 +41,7 @@ using Tom::Constants::disable_incrementing;
|
||||
using Tom::Constants::disable_timestamps;
|
||||
using Tom::Constants::fillable;
|
||||
using Tom::Constants::fillable_up;
|
||||
using Tom::Constants::force;
|
||||
using Tom::Constants::foreign_key;
|
||||
using Tom::Constants::foreign_key_up;
|
||||
using Tom::Constants::fullpath;
|
||||
@@ -84,7 +85,7 @@ namespace Tom::Commands::Make
|
||||
/* public */
|
||||
|
||||
ModelCommand::ModelCommand(Application &application, QCommandLineParser &parser)
|
||||
: Command(application, parser)
|
||||
: MakeCommand(application, parser)
|
||||
{}
|
||||
|
||||
const std::vector<PositionalArgument> &ModelCommand::positionalArguments() const
|
||||
@@ -186,6 +187,9 @@ QList<QCommandLineOption> ModelCommand::optionsSignature() const
|
||||
"paths are pre-resolved absolute paths")},
|
||||
{fullpath, QStringLiteral("Output the full path of the created "
|
||||
"model")},
|
||||
{{QChar('f'),
|
||||
force}, QStringLiteral("Overwrite the model class if already "
|
||||
"exists")},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -227,6 +231,7 @@ int ModelCommand::run()
|
||||
const auto [className, cmdOptions] = prepareModelClassNames(argument(NAME),
|
||||
createCmdOptions());
|
||||
|
||||
// Unused warnings
|
||||
showUnusedOptionsWarnings(cmdOptions);
|
||||
|
||||
if (!m_unusedBtmOptions.empty() || m_shownUnusedForeignKey ||
|
||||
@@ -234,6 +239,10 @@ int ModelCommand::run()
|
||||
)
|
||||
newLine();
|
||||
|
||||
// Check whether a model file already exists and create parent folder if needed
|
||||
prepareFileSystem(QStringLiteral("model"), getModelPath(), className.toLower(),
|
||||
className);
|
||||
|
||||
// Ready to write the model to the disk 🧨✨
|
||||
writeModel(className, cmdOptions);
|
||||
|
||||
@@ -275,7 +284,8 @@ ModelCommand::prepareModelClassNames(QString &&className, CmdOptions &&cmdOption
|
||||
] = cmdOptions;
|
||||
|
||||
// Validate the model class names
|
||||
throwIfContainsNamespaceOrPath(className, QStringLiteral("argument 'name'"));
|
||||
MakeCommand::throwIfContainsNamespaceOrPath(QStringLiteral("model"), className,
|
||||
QStringLiteral("argument 'name'"));
|
||||
throwIfContainsNamespaceOrPath(oneToOneList,
|
||||
QStringLiteral("option --one-to-one"));
|
||||
throwIfContainsNamespaceOrPath(oneToManyList,
|
||||
@@ -285,9 +295,11 @@ ModelCommand::prepareModelClassNames(QString &&className, CmdOptions &&cmdOption
|
||||
throwIfContainsNamespaceOrPath(belongsToManyList,
|
||||
QStringLiteral("option --belongs-to-many"));
|
||||
throwIfContainsNamespaceOrPath(pivotClasses,
|
||||
QStringLiteral("option --pivot"));
|
||||
QStringLiteral("option --pivot"),
|
||||
QStringLiteral("pivot model"));
|
||||
throwIfContainsNamespaceOrPath(pivotInverseClasses,
|
||||
QStringLiteral("option --pivot-inverse"));
|
||||
QStringLiteral("option --pivot-inverse"),
|
||||
QStringLiteral("pivot model"));
|
||||
|
||||
oneToOneList = StringUtils::studly(std::move(oneToOneList));
|
||||
oneToManyList = StringUtils::studly(std::move(oneToManyList));
|
||||
@@ -484,6 +496,11 @@ RelationsOrder ModelCommand::relationsOrder()
|
||||
|
||||
fspath ModelCommand::getModelPath() const
|
||||
{
|
||||
static fspath cached;
|
||||
|
||||
if (!cached.empty())
|
||||
return cached;
|
||||
|
||||
// Default location
|
||||
if (!isSet(path_))
|
||||
return application().getModelsPath();
|
||||
@@ -503,7 +520,7 @@ fspath ModelCommand::getModelPath() const
|
||||
QStringLiteral("Models path '%1' exists and it's not a directory.")
|
||||
.arg(modelsPath.c_str()));
|
||||
|
||||
return modelsPath;
|
||||
return cached = modelsPath;
|
||||
}
|
||||
|
||||
const std::unordered_set<QString> &ModelCommand::relationNames()
|
||||
@@ -525,6 +542,7 @@ void ModelCommand::createMigration(const QString &className) const
|
||||
table.append(QChar('s'));
|
||||
|
||||
call(MakeMigration, {longOption(create_, table),
|
||||
boolCmd(force),
|
||||
QStringLiteral("create_%1_table").arg(std::move(table))});
|
||||
}
|
||||
|
||||
@@ -534,37 +552,25 @@ void ModelCommand::createSeeder(const QString &className) const
|
||||
|
||||
// FUTURE tom, add hidden options support to the tom's parser, add --table option for the make:seeder command and pass singular table name for pivot models because currently the make:seeder command generates eg. taggeds table name (even if this table name is in the commented code), command to reproduce: tom make:model Tagged --pivot-model --seeder silverqx
|
||||
|
||||
call(MakeSeeder, {std::move(seederClassName)});
|
||||
call(MakeSeeder, {boolCmd(force), std::move(seederClassName)});
|
||||
}
|
||||
|
||||
/* private */
|
||||
|
||||
void ModelCommand::throwIfContainsNamespaceOrPath(
|
||||
const std::vector<QStringList> &classNames, const QString &source)
|
||||
const std::vector<QStringList> &classNames, const QString &source,
|
||||
const QString &commandType)
|
||||
{
|
||||
for (const auto &classNameList : classNames)
|
||||
throwIfContainsNamespaceOrPath(classNameList, source);
|
||||
throwIfContainsNamespaceOrPath(classNameList, source, commandType);
|
||||
}
|
||||
|
||||
void ModelCommand::throwIfContainsNamespaceOrPath(const QStringList &classNames,
|
||||
const QString &source)
|
||||
void ModelCommand::throwIfContainsNamespaceOrPath(
|
||||
const QStringList &classNames, const QString &source,
|
||||
const QString &commandType)
|
||||
{
|
||||
for (const auto &className : classNames)
|
||||
throwIfContainsNamespaceOrPath(className, source);
|
||||
}
|
||||
|
||||
void ModelCommand::throwIfContainsNamespaceOrPath(const QString &className,
|
||||
const QString &source)
|
||||
{
|
||||
if (!className.contains(QStringLiteral("::")) && !className.contains(QChar('/')) &&
|
||||
!className.contains(QChar('\\'))
|
||||
)
|
||||
return;
|
||||
|
||||
throw Exceptions::InvalidArgumentError(
|
||||
QStringLiteral("Namespace or path is not allowed in the model "
|
||||
"names (%1).")
|
||||
.arg(source));
|
||||
MakeCommand::throwIfContainsNamespaceOrPath(commandType, className, source);
|
||||
}
|
||||
|
||||
} // namespace Tom::Commands::Make
|
||||
|
||||
@@ -15,10 +15,12 @@ using Orm::Constants::NAME;
|
||||
|
||||
using StringUtils = Orm::Tiny::Utils::String;
|
||||
|
||||
using Tom::Constants::force;
|
||||
using Tom::Constants::fullpath;
|
||||
using Tom::Constants::path_;
|
||||
using Tom::Constants::path_up;
|
||||
using Tom::Constants::realpath_;
|
||||
using Tom::Constants::seeder;
|
||||
|
||||
TINYORM_BEGIN_COMMON_NAMESPACE
|
||||
|
||||
@@ -28,7 +30,7 @@ namespace Tom::Commands::Make
|
||||
/* public */
|
||||
|
||||
SeederCommand::SeederCommand(Application &application, QCommandLineParser &parser)
|
||||
: Command(application, parser)
|
||||
: MakeCommand(application, parser)
|
||||
{}
|
||||
|
||||
const std::vector<PositionalArgument> &SeederCommand::positionalArguments() const
|
||||
@@ -43,11 +45,14 @@ const std::vector<PositionalArgument> &SeederCommand::positionalArguments() cons
|
||||
QList<QCommandLineOption> SeederCommand::optionsSignature() const
|
||||
{
|
||||
return {
|
||||
{path_, QStringLiteral("The location where the seeder file should be "
|
||||
"created"), path_up}, // Value
|
||||
{realpath_, QStringLiteral("Indicate that any provided seeder file paths are "
|
||||
"pre-resolved absolute paths")},
|
||||
{fullpath, QStringLiteral("Output the full path of the created seeder")},
|
||||
{path_, QStringLiteral("The location where the seeder file should be "
|
||||
"created"), path_up}, // Value
|
||||
{realpath_, QStringLiteral("Indicate that any provided seeder file paths are "
|
||||
"pre-resolved absolute paths")},
|
||||
{fullpath, QStringLiteral("Output the full path of the created seeder")},
|
||||
|
||||
{{QChar('f'),
|
||||
force}, QStringLiteral("Overwrite the seeder class if already exists")},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -57,6 +62,9 @@ int SeederCommand::run()
|
||||
|
||||
const auto className = prepareSeederClassName(argument(NAME));
|
||||
|
||||
// Check whether a seeder file already exists and create parent folder if needed
|
||||
prepareFileSystem(seeder, getSeederPath(), className.toLower(), className);
|
||||
|
||||
// Ready to write the seeder to the disk 🧨✨
|
||||
writeSeeder(className);
|
||||
|
||||
@@ -68,7 +76,8 @@ int SeederCommand::run()
|
||||
QString SeederCommand::prepareSeederClassName(QString &&className)
|
||||
{
|
||||
// Validate the seeder name
|
||||
throwIfContainsNamespaceOrPath(className);
|
||||
throwIfContainsNamespaceOrPath(QStringLiteral("seeder"), className,
|
||||
QStringLiteral("argument 'name'"));
|
||||
|
||||
static const auto Seeder = QStringLiteral("Seeder");
|
||||
static const auto Seeder_lc = QStringLiteral("seeder");
|
||||
@@ -106,6 +115,11 @@ void SeederCommand::writeSeeder(const QString &className) const
|
||||
|
||||
fspath SeederCommand::getSeederPath() const
|
||||
{
|
||||
static fspath cached;
|
||||
|
||||
if (!cached.empty())
|
||||
return cached;
|
||||
|
||||
// Default location
|
||||
if (!isSet(path_))
|
||||
return application().getSeedersPath();
|
||||
@@ -125,18 +139,7 @@ fspath SeederCommand::getSeederPath() const
|
||||
QStringLiteral("Seeders path '%1' exists and it's not a directory.")
|
||||
.arg(seedersPath.c_str()));
|
||||
|
||||
return seedersPath;
|
||||
}
|
||||
|
||||
void SeederCommand::throwIfContainsNamespaceOrPath(const QString &className)
|
||||
{
|
||||
if (!className.contains(QStringLiteral("::")) && !className.contains(QChar('/')) &&
|
||||
!className.contains(QChar('\\'))
|
||||
)
|
||||
return;
|
||||
|
||||
throw Exceptions::InvalidArgumentError(
|
||||
"Namespace or path is not allowed in the seeder name.");
|
||||
return cached = seedersPath;
|
||||
}
|
||||
|
||||
} // namespace Tom::Commands::Make
|
||||
|
||||
@@ -7,11 +7,8 @@
|
||||
#include <orm/tiny/utils/string.hpp>
|
||||
|
||||
#include "tom/commands/make/stubs/migrationstubs.hpp"
|
||||
#include "tom/exceptions/invalidargumenterror.hpp"
|
||||
#include "tom/tomconstants.hpp"
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
using fspath = std::filesystem::path;
|
||||
|
||||
using StringUtils = Orm::Tiny::Utils::String;
|
||||
@@ -35,15 +32,11 @@ fspath MigrationCreator::create(
|
||||
auto migrationPath = getPath(std::move(datetimePrefix), name, std::move(extension),
|
||||
migrationsPath);
|
||||
|
||||
throwIfMigrationAlreadyExists(name, migrationsPath);
|
||||
|
||||
/* First we will get the stub file for the migration, which serves as a type
|
||||
of template for the migration. Once we have those we will populate the
|
||||
various place-holders, and save the file. */
|
||||
auto stub = getStub(table, create);
|
||||
|
||||
ensureDirectoryExists(migrationsPath);
|
||||
|
||||
// Output it as binary stream to force line endings to LF
|
||||
std::ofstream(migrationPath, std::ios::out | std::ios::binary)
|
||||
<< populateStub(name, std::move(stub), table);
|
||||
@@ -112,42 +105,6 @@ QString MigrationCreator::getClassName(const QString &name)
|
||||
return StringUtils::studly(name);
|
||||
}
|
||||
|
||||
void MigrationCreator::ensureDirectoryExists(const fspath &path)
|
||||
{
|
||||
if (fs::exists(path) && fs::is_directory(path))
|
||||
return;
|
||||
|
||||
fs::create_directories(path);
|
||||
}
|
||||
|
||||
/* private */
|
||||
|
||||
void MigrationCreator::throwIfMigrationAlreadyExists(const QString &name,
|
||||
const fspath &migrationsPath)
|
||||
{
|
||||
// Nothing to check
|
||||
if (!fs::exists(migrationsPath))
|
||||
return;
|
||||
|
||||
using options = fs::directory_options;
|
||||
|
||||
for (const auto &entry :
|
||||
fs::directory_iterator(migrationsPath, options::skip_permission_denied)
|
||||
) {
|
||||
// Check only files
|
||||
if (!entry.is_regular_file())
|
||||
continue;
|
||||
|
||||
// Extract migration name without datetime prefix and extension
|
||||
auto entryName = QString::fromStdString(entry.path().stem().string())
|
||||
.mid(DateTimePrefix.size() + 1);
|
||||
|
||||
if (entryName == name)
|
||||
throw Exceptions::InvalidArgumentError(
|
||||
QStringLiteral("A '%1' migration already exists.").arg(name));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Tom::Commands::Make::Support
|
||||
|
||||
TINYORM_END_COMMON_NAMESPACE
|
||||
|
||||
@@ -17,9 +17,6 @@
|
||||
|
||||
#include "tom/commands/make/modelcommandconcepts.hpp"
|
||||
#include "tom/commands/make/stubs/modelstubs.hpp"
|
||||
#include "tom/exceptions/invalidargumenterror.hpp"
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
using fspath = std::filesystem::path;
|
||||
|
||||
@@ -74,10 +71,6 @@ fspath ModelCreator::create(const QString &className, const CmdOptions &cmdOptio
|
||||
|
||||
auto modelPath = getPath(basename, modelsPath);
|
||||
|
||||
throwIfModelAlreadyExists(className, basename, modelsPath);
|
||||
|
||||
ensureDirectoryExists(modelsPath);
|
||||
|
||||
// Output it as binary stream to force line endings to LF
|
||||
std::ofstream(modelPath, std::ios::out | std::ios::binary)
|
||||
<< populateStub(className, cmdOptions, isSetPreserveOrder);
|
||||
@@ -92,14 +85,6 @@ fspath ModelCreator::getPath(const QString &basename, const fspath &path)
|
||||
return path / (basename.toStdString() + ".hpp");
|
||||
}
|
||||
|
||||
void ModelCreator::ensureDirectoryExists(const fspath &path)
|
||||
{
|
||||
if (fs::exists(path) && fs::is_directory(path))
|
||||
return;
|
||||
|
||||
fs::create_directories(path);
|
||||
}
|
||||
|
||||
std::string ModelCreator::populateStub(
|
||||
const QString &className, const CmdOptions &cmdOptions,
|
||||
const bool isSetPreserveOrder)
|
||||
@@ -1062,33 +1047,6 @@ QString ModelCreator::joinRelationsList(RelationsWithOrder &&relationsList)
|
||||
return relationsQList.join(NEWLINE);
|
||||
}
|
||||
|
||||
/* private */
|
||||
|
||||
void ModelCreator::throwIfModelAlreadyExists(
|
||||
const QString &className, const QString &basename, const fspath &modelsPath)
|
||||
{
|
||||
// Nothing to check
|
||||
if (!fs::exists(modelsPath))
|
||||
return;
|
||||
|
||||
using options = fs::directory_options;
|
||||
|
||||
for (const auto &entry :
|
||||
fs::directory_iterator(modelsPath, options::skip_permission_denied)
|
||||
) {
|
||||
// Check only files
|
||||
if (!entry.is_regular_file())
|
||||
continue;
|
||||
|
||||
// Extract base filename without the extension
|
||||
auto entryName = QString::fromStdString(entry.path().stem().string());
|
||||
|
||||
if (entryName == basename)
|
||||
throw Exceptions::InvalidArgumentError(
|
||||
QStringLiteral("A '%1' model already exists.").arg(className));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Tom::Commands::Make::Support
|
||||
|
||||
TINYORM_END_COMMON_NAMESPACE
|
||||
|
||||
@@ -5,9 +5,6 @@
|
||||
#include <orm/tiny/utils/string.hpp>
|
||||
|
||||
#include "tom/commands/make/stubs/seederstubs.hpp"
|
||||
#include "tom/exceptions/invalidargumenterror.hpp"
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
using fspath = std::filesystem::path;
|
||||
|
||||
@@ -28,10 +25,6 @@ fspath SeederCreator::create(const QString &className, fspath &&seedersPath) con
|
||||
|
||||
auto seederPath = getPath(basename, seedersPath);
|
||||
|
||||
throwIfSeederAlreadyExists(className, basename, seedersPath);
|
||||
|
||||
ensureDirectoryExists(seedersPath);
|
||||
|
||||
/* Populate the various place-holders, and save the file.
|
||||
Output it as binary stream to force line endings to LF. */
|
||||
std::ofstream(seederPath, std::ios::out | std::ios::binary)
|
||||
@@ -47,14 +40,6 @@ fspath SeederCreator::getPath(const QString &basename, const fspath &path)
|
||||
return path / (basename.toStdString() + ".hpp");
|
||||
}
|
||||
|
||||
void SeederCreator::ensureDirectoryExists(const fspath &path)
|
||||
{
|
||||
if (fs::exists(path) && fs::is_directory(path))
|
||||
return;
|
||||
|
||||
fs::create_directories(path);
|
||||
}
|
||||
|
||||
std::string
|
||||
SeederCreator::populateStub(const QString &className, QString &&table)
|
||||
{
|
||||
@@ -87,34 +72,6 @@ QString SeederCreator::getTableName(QString className)
|
||||
return StringUtils::snake(className);
|
||||
}
|
||||
|
||||
/* private */
|
||||
|
||||
void SeederCreator::throwIfSeederAlreadyExists(
|
||||
const QString &className, const QString &basename,
|
||||
const fspath &seedersPath) const
|
||||
{
|
||||
// Nothing to check
|
||||
if (!fs::exists(seedersPath))
|
||||
return;
|
||||
|
||||
using options = fs::directory_options;
|
||||
|
||||
for (const auto &entry :
|
||||
fs::directory_iterator(seedersPath, options::skip_permission_denied)
|
||||
) {
|
||||
// Check only files
|
||||
if (!entry.is_regular_file())
|
||||
continue;
|
||||
|
||||
// Extract base filename without the extension
|
||||
auto entryName = QString::fromStdString(entry.path().stem().string());
|
||||
|
||||
if (entryName == basename)
|
||||
throw Exceptions::InvalidArgumentError(
|
||||
QStringLiteral("A '%1' seeder already exists.").arg(className));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Tom::Commands::Make::Support
|
||||
|
||||
TINYORM_END_COMMON_NAMESPACE
|
||||
|
||||
@@ -187,7 +187,8 @@ _tom() {
|
||||
'--table=[The table to migrate]:table name' \
|
||||
'--path=[The location where the migration file should be created]:folder path:_files -/' \
|
||||
'--realpath[Indicate any provided migration file paths are pre-resolved absolute paths]' \
|
||||
'--fullpath[Output the full path of the migration]'
|
||||
'--fullpath[Output the full path of the migration]' \
|
||||
'(-f --force)'{-f,--force}'[Overwrite the model class if already exists]'
|
||||
;;
|
||||
|
||||
make:model)
|
||||
@@ -220,7 +221,8 @@ _tom() {
|
||||
'(-o --preserve-order)'{-o,--preserve-order}'[Preserve relations order defined on the command-line]' \
|
||||
'--path=[The location where the migration file should be created]:folder path:_files -/' \
|
||||
'--realpath[Indicate any provided migration file paths are pre-resolved absolute paths]' \
|
||||
'--fullpath[Output the full path of the migration]'
|
||||
'--fullpath[Output the full path of the migration]' \
|
||||
'(-f --force)'{-f,--force}'[Overwrite the migration file if already exists]'
|
||||
;;
|
||||
|
||||
make:seeder)
|
||||
@@ -229,7 +231,8 @@ _tom() {
|
||||
'1::class name:()' \
|
||||
'--path=[The location where the migration file should be created]:folder path:_files -/' \
|
||||
'--realpath[Indicate any provided migration file paths are pre-resolved absolute paths]' \
|
||||
'--fullpath[Output the full path of the migration]'
|
||||
'--fullpath[Output the full path of the migration]' \
|
||||
'(-f --force)'{-f,--force}'[Overwrite the seeder class if already exists]'
|
||||
;;
|
||||
|
||||
migrate:fresh)
|
||||
|
||||
Reference in New Issue
Block a user