mirror of
https://github.com/silverqx/TinyORM.git
synced 2025-12-30 15:29:36 -06:00
added schema builder 🔥🚀✨
Added practically everything I wanted to have in except for updating columns. Needed to name the schema namespace as Orm::SchemaNs to avoid collision with the Orm::Schema class. - unit tests with great coverage - new schema constants - a new prefix_indexes and engine DB conncetion configurations Others: - IsModel tag - enhanced columnize in the BaseGrammar - used a new columnize logic in all grammars - new constants - new container utils class for joining containers - new DB::driver() getter for QSqlDriver - avoid possible crash in tests with pretend, added empty log checks - clang tidy, excluded to word from short variable names
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
---
|
||||
Checks: '-*,bugprone-*,clang-*,concurrency-*,cppcoreguidelines-*,google-*,llvm-*,misc-*,modernize-*,performance-*,portability-*,readability-*,-bugprone-easily-swappable-parameters,-cppcoreguidelines-avoid-c-arrays,-cppcoreguidelines-avoid-magic-numbers,-cppcoreguidelines-avoid-non-const-global-variables,-cppcoreguidelines-c-copy-assignment-signature,-cppcoreguidelines-macro-usage,-cppcoreguidelines-non-private-member-variables-in-classes,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-cppcoreguidelines-pro-type-const-cast,-cppcoreguidelines-pro-type-reinterpret-cast,-cppcoreguidelines-pro-type-vararg,-cppcoreguidelines-special-member-functions,-google-default-arguments,-google-readability-braces-around-statements,-google-readability-function-size,-google-readability-todo,-llvm-header-guard,-misc-non-private-member-variables-in-classes,-modernize-use-nodiscard,-modernize-use-trailing-return-type,-performance-move-const-arg,-readability-braces-around-statements,-readability-convert-member-functions-to-static,-readability-magic-numbers'
|
||||
Checks: '-*,bugprone-*,clang-*,concurrency-*,cppcoreguidelines-*,google-*,llvm-*,misc-*,modernize-*,performance-*,portability-*,readability-*,-bugprone-easily-swappable-parameters,-cppcoreguidelines-avoid-c-arrays,-cppcoreguidelines-avoid-magic-numbers,-cppcoreguidelines-avoid-non-const-global-variables,-cppcoreguidelines-c-copy-assignment-signature,-cppcoreguidelines-macro-usage,-cppcoreguidelines-non-private-member-variables-in-classes,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-cppcoreguidelines-pro-type-const-cast,-cppcoreguidelines-pro-type-reinterpret-cast,-cppcoreguidelines-pro-type-vararg,-cppcoreguidelines-special-member-functions,-google-default-arguments,-google-readability-braces-around-statements,-google-readability-function-size,-google-readability-todo,-llvm-else-after-return,-llvm-header-guard,-misc-non-private-member-variables-in-classes,-modernize-use-nodiscard,-modernize-use-trailing-return-type,-performance-move-const-arg,-readability-braces-around-statements,-readability-convert-member-functions-to-static,-readability-magic-numbers'
|
||||
WarningsAsErrors: '*'
|
||||
HeaderFilterRegex: 'orm/.+\.(h|hpp)$'
|
||||
FormatStyle: none
|
||||
@@ -9,3 +9,5 @@ CheckOptions:
|
||||
value: '5'
|
||||
- key: llvm-namespace-comment.ShortNamespaceLines
|
||||
value: '5'
|
||||
- key: readability-identifier-length.IgnoredParameterNames
|
||||
value: '^to$'
|
||||
|
||||
@@ -5,9 +5,15 @@ function(tiny_sources out_headers out_sources)
|
||||
set(headers)
|
||||
|
||||
if(TINY_EXTERN_CONSTANTS)
|
||||
list(APPEND headers constants_extern.hpp)
|
||||
list(APPEND headers
|
||||
constants_extern.hpp
|
||||
schema/schemaconstants_extern.hpp
|
||||
)
|
||||
else()
|
||||
list(APPEND headers constants_inline.hpp)
|
||||
list(APPEND headers
|
||||
constants_inline.hpp
|
||||
schema/schemaconstants_inline.hpp
|
||||
)
|
||||
endif()
|
||||
|
||||
list(APPEND headers
|
||||
@@ -61,6 +67,12 @@ function(tiny_sources out_headers out_sources)
|
||||
query/processors/processor.hpp
|
||||
query/processors/sqliteprocessor.hpp
|
||||
query/querybuilder.hpp
|
||||
schema.hpp
|
||||
schema/blueprint.hpp
|
||||
schema/columndefinition.hpp
|
||||
schema/columndefinitionreference.hpp
|
||||
schema/foreignidcolumndefinitionreference.hpp
|
||||
schema/foreignkeydefinitionreference.hpp
|
||||
schema/grammars/mysqlschemagrammar.hpp
|
||||
schema/grammars/postgresschemagrammar.hpp
|
||||
schema/grammars/schemagrammar.hpp
|
||||
@@ -68,6 +80,8 @@ function(tiny_sources out_headers out_sources)
|
||||
schema/mysqlschemabuilder.hpp
|
||||
schema/postgresschemabuilder.hpp
|
||||
schema/schemabuilder.hpp
|
||||
schema/schemaconstants.hpp
|
||||
schema/schematypes.hpp
|
||||
schema/sqliteschemabuilder.hpp
|
||||
sqliteconnection.hpp
|
||||
support/configurationoptionsparser.hpp
|
||||
@@ -75,6 +89,7 @@ function(tiny_sources out_headers out_sources)
|
||||
support/databaseconnectionsmap.hpp
|
||||
types/log.hpp
|
||||
types/statementscounter.hpp
|
||||
utils/container.hpp
|
||||
utils/fs.hpp
|
||||
utils/query.hpp
|
||||
utils/thread.hpp
|
||||
@@ -123,7 +138,10 @@ function(tiny_sources out_headers out_sources)
|
||||
set(sources)
|
||||
|
||||
if(TINY_EXTERN_CONSTANTS)
|
||||
list(APPEND sources constants_extern.cpp)
|
||||
list(APPEND sources
|
||||
constants_extern.cpp
|
||||
schema/schemaconstants_extern.cpp
|
||||
)
|
||||
endif()
|
||||
|
||||
list(APPEND sources
|
||||
@@ -158,8 +176,13 @@ function(tiny_sources out_headers out_sources)
|
||||
query/processors/processor.cpp
|
||||
query/processors/sqliteprocessor.cpp
|
||||
query/querybuilder.cpp
|
||||
schema.cpp
|
||||
schema/blueprint.cpp
|
||||
schema/foreignidcolumndefinitionreference.cpp
|
||||
schema/foreignkeydefinitionreference.cpp
|
||||
schema/grammars/mysqlschemagrammar.cpp
|
||||
schema/grammars/postgresschemagrammar.cpp
|
||||
schema/grammars/schemagrammar.cpp
|
||||
schema/grammars/sqliteschemagrammar.cpp
|
||||
schema/mysqlschemabuilder.cpp
|
||||
schema/postgresschemabuilder.cpp
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
INCLUDEPATH += $$PWD
|
||||
|
||||
extern_constants: \
|
||||
headersList += $$PWD/orm/constants_extern.hpp
|
||||
headersList += \
|
||||
$$PWD/orm/constants_extern.hpp \
|
||||
$$PWD/orm/schema/schemaconstants_extern.hpp
|
||||
else: \
|
||||
headersList += $$PWD/orm/constants_inline.hpp
|
||||
headersList += \
|
||||
$$PWD/orm/constants_inline.hpp \
|
||||
$$PWD/orm/schema/schemaconstants_inline.hpp
|
||||
|
||||
headersList += \
|
||||
$$PWD/orm/basegrammar.hpp \
|
||||
@@ -59,6 +63,12 @@ headersList += \
|
||||
$$PWD/orm/query/processors/processor.hpp \
|
||||
$$PWD/orm/query/processors/sqliteprocessor.hpp \
|
||||
$$PWD/orm/query/querybuilder.hpp \
|
||||
$$PWD/orm/schema.hpp \
|
||||
$$PWD/orm/schema/blueprint.hpp \
|
||||
$$PWD/orm/schema/columndefinition.hpp \
|
||||
$$PWD/orm/schema/columndefinitionreference.hpp \
|
||||
$$PWD/orm/schema/foreignidcolumndefinitionreference.hpp \
|
||||
$$PWD/orm/schema/foreignkeydefinitionreference.hpp \
|
||||
$$PWD/orm/schema/grammars/mysqlschemagrammar.hpp \
|
||||
$$PWD/orm/schema/grammars/postgresschemagrammar.hpp \
|
||||
$$PWD/orm/schema/grammars/schemagrammar.hpp \
|
||||
@@ -66,6 +76,8 @@ headersList += \
|
||||
$$PWD/orm/schema/mysqlschemabuilder.hpp \
|
||||
$$PWD/orm/schema/postgresschemabuilder.hpp \
|
||||
$$PWD/orm/schema/schemabuilder.hpp \
|
||||
$$PWD/orm/schema/schemaconstants.hpp \
|
||||
$$PWD/orm/schema/schematypes.hpp \
|
||||
$$PWD/orm/schema/sqliteschemabuilder.hpp \
|
||||
$$PWD/orm/sqliteconnection.hpp \
|
||||
$$PWD/orm/support/configurationoptionsparser.hpp \
|
||||
@@ -73,6 +85,7 @@ headersList += \
|
||||
$$PWD/orm/support/databaseconnectionsmap.hpp \
|
||||
$$PWD/orm/types/log.hpp \
|
||||
$$PWD/orm/types/statementscounter.hpp \
|
||||
$$PWD/orm/utils/container.hpp \
|
||||
$$PWD/orm/utils/fs.hpp \
|
||||
$$PWD/orm/utils/query.hpp \
|
||||
$$PWD/orm/utils/thread.hpp \
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
#include "orm/macros/systemheader.hpp"
|
||||
TINY_SYSTEM_HEADER
|
||||
|
||||
#include "orm/ormconcepts.hpp"
|
||||
#include "orm/ormtypes.hpp"
|
||||
#include "orm/utils/container.hpp"
|
||||
|
||||
TINYORM_BEGIN_COMMON_NAMESPACE
|
||||
|
||||
@@ -16,12 +18,6 @@ namespace Query
|
||||
class Expression;
|
||||
} // namespace Query
|
||||
|
||||
/*! QString container concept (QStringList or QVector<QString>). */
|
||||
template<typename T>
|
||||
concept ColumnContainer = std::convertible_to<T, const QStringList &> ||
|
||||
std::convertible_to<T, const QVector<QString> &> ||
|
||||
std::convertible_to<T, const QVector<Column> &>;
|
||||
|
||||
/*! Concept for container passed to the parametrize() method (QVariantMap
|
||||
or QVector<QString>). */
|
||||
template<typename T>
|
||||
@@ -33,6 +29,7 @@ namespace Query
|
||||
{
|
||||
Q_DISABLE_COPY(BaseGrammar)
|
||||
|
||||
protected:
|
||||
/*! Expression alias. */
|
||||
using Expression = Query::Expression;
|
||||
|
||||
@@ -82,9 +79,12 @@ namespace Query
|
||||
QString unqualifyColumn(const QString &column) const;
|
||||
|
||||
protected:
|
||||
/*! Convert the vector of column names into a delimited string. */
|
||||
/*! Convert the vector of column names into a wrapped comma delimited string. */
|
||||
template<ColumnContainer T>
|
||||
inline QString columnize(const T &columns) const;
|
||||
QString columnize(T &&columns) const;
|
||||
/*! Convert the vector of column names into a comma delimited string. */
|
||||
template<ColumnContainer T>
|
||||
QString columnizeWithoutWrap(T &&columns) const;
|
||||
|
||||
/*! Create query parameter place-holders for the vector. */
|
||||
template<Parametrize Container>
|
||||
@@ -110,16 +110,20 @@ namespace Query
|
||||
// FEATURE qt6, use everywhere QLatin1String("") instead of = "", BUT Qt6 has char8_t ctor, so u"" can be used, I will wait with this problem silverqx
|
||||
/*! The grammar table prefix. */
|
||||
QString m_tablePrefix {};
|
||||
|
||||
private:
|
||||
/*! Convert the vector of column names into a delimited string. */
|
||||
QString columnizeInternal(const QVector<QString> &columns) const;
|
||||
};
|
||||
|
||||
template<ColumnContainer T>
|
||||
QString BaseGrammar::columnize(const T &columns) const
|
||||
QString BaseGrammar::columnize(T &&columns) const
|
||||
{
|
||||
return columnizeInternal(wrapArray(columns));
|
||||
return columnizeWithoutWrap(wrapArray(std::forward<T>(columns)));
|
||||
}
|
||||
|
||||
/* I leave this method here because it has meaningful name, not make it inline to avoid
|
||||
utils/container.hpp include in the header file. */
|
||||
template<ColumnContainer T>
|
||||
QString BaseGrammar::columnizeWithoutWrap(T &&columns) const
|
||||
{
|
||||
return Utils::Container::join(std::forward<T>(columns));
|
||||
}
|
||||
|
||||
QString BaseGrammar::getTablePrefix() const
|
||||
@@ -168,7 +172,7 @@ namespace Query
|
||||
compiledParameters << parameter(value);
|
||||
|
||||
// CUR1 QString allocation 😟 solve everywhere 😭 silverqx
|
||||
return compiledParameters.join(COMMA);
|
||||
return columnizeWithoutWrap(compiledParameters);
|
||||
}
|
||||
|
||||
} // namespace Orm
|
||||
|
||||
@@ -49,6 +49,8 @@ namespace Orm::Constants
|
||||
SHAREDLIB_EXPORT extern const QString UPDATED_AT;
|
||||
SHAREDLIB_EXPORT extern const QString PARENTH_ONE;
|
||||
SHAREDLIB_EXPORT extern const QString NEWLINE;
|
||||
SHAREDLIB_EXPORT extern const QString SPACE_IN;
|
||||
SHAREDLIB_EXPORT extern const QString NOSPACE;
|
||||
|
||||
SHAREDLIB_EXPORT extern const QString QMYSQL;
|
||||
SHAREDLIB_EXPORT extern const QString QPSQL;
|
||||
@@ -70,10 +72,12 @@ namespace Orm::Constants
|
||||
SHAREDLIB_EXPORT extern const QString prefix_;
|
||||
SHAREDLIB_EXPORT extern const QString options_;
|
||||
SHAREDLIB_EXPORT extern const QString strict_;
|
||||
SHAREDLIB_EXPORT extern const QString engine_;
|
||||
|
||||
SHAREDLIB_EXPORT extern const QString isolation_level;
|
||||
SHAREDLIB_EXPORT extern const QString foreign_key_constraints;
|
||||
SHAREDLIB_EXPORT extern const QString check_database_exists;
|
||||
SHAREDLIB_EXPORT extern const QString prefix_indexes;
|
||||
|
||||
SHAREDLIB_EXPORT extern const QString H127001;
|
||||
SHAREDLIB_EXPORT extern const QString LOCALHOST;
|
||||
@@ -86,6 +90,10 @@ namespace Orm::Constants
|
||||
SHAREDLIB_EXPORT extern const QString PUBLIC;
|
||||
SHAREDLIB_EXPORT extern const QString UTF8;
|
||||
SHAREDLIB_EXPORT extern const QString UTF8MB4;
|
||||
SHAREDLIB_EXPORT extern const QString InnoDB;
|
||||
SHAREDLIB_EXPORT extern const QString MyISAM;
|
||||
|
||||
SHAREDLIB_EXPORT extern const QString NotImplemented;
|
||||
|
||||
// Comparison/logical/search operators
|
||||
SHAREDLIB_EXPORT extern const QString EQ;
|
||||
|
||||
@@ -14,6 +14,7 @@ TINYORM_BEGIN_COMMON_NAMESPACE
|
||||
/*! Namespace constains common chars and strings. */
|
||||
namespace Orm::Constants
|
||||
{
|
||||
// CUR1 sort it silverqx
|
||||
|
||||
// Common chars
|
||||
inline const QChar SPACE = QChar(' ');
|
||||
@@ -48,6 +49,8 @@ namespace Orm::Constants
|
||||
inline const QString UPDATED_AT = QStringLiteral("updated_at");
|
||||
inline const QString PARENTH_ONE = QStringLiteral("(%1)");
|
||||
inline const QString NEWLINE = QStringLiteral("\n");
|
||||
inline const QString SPACE_IN = QStringLiteral("%1 %2");
|
||||
inline const QString NOSPACE = QStringLiteral("%1%2");
|
||||
|
||||
inline const QString QMYSQL = QStringLiteral("QMYSQL");
|
||||
inline const QString QPSQL = QStringLiteral("QPSQL");
|
||||
@@ -69,6 +72,7 @@ namespace Orm::Constants
|
||||
inline const QString prefix_ = QStringLiteral("prefix");
|
||||
inline const QString options_ = QStringLiteral("options");
|
||||
inline const QString strict_ = QStringLiteral("strict");
|
||||
inline const QString engine_ = QStringLiteral("engine");
|
||||
|
||||
inline const QString
|
||||
isolation_level = QStringLiteral("isolation_level");
|
||||
@@ -76,6 +80,8 @@ namespace Orm::Constants
|
||||
foreign_key_constraints = QStringLiteral("foreign_key_constraints");
|
||||
inline const QString
|
||||
check_database_exists = QStringLiteral("check_database_exists");
|
||||
inline const QString
|
||||
prefix_indexes = QStringLiteral("prefix_indexes");
|
||||
|
||||
inline const QString H127001 = QStringLiteral("127.0.0.1");
|
||||
inline const QString LOCALHOST = QStringLiteral("localhost");
|
||||
@@ -88,6 +94,10 @@ namespace Orm::Constants
|
||||
inline const QString PUBLIC = QStringLiteral("public");
|
||||
inline const QString UTF8 = QStringLiteral("utf8");
|
||||
inline const QString UTF8MB4 = QStringLiteral("utf8mb4");
|
||||
inline const QString InnoDB = QStringLiteral("InnoDB");
|
||||
inline const QString MyISAM = QStringLiteral("MyISAM");
|
||||
|
||||
inline const QString NotImplemented = QStringLiteral("Not implemented :/.");
|
||||
|
||||
// Comparison/logical/search operators
|
||||
inline const QString EQ = QStringLiteral("=");
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace Processors
|
||||
}
|
||||
} // namespace Query
|
||||
|
||||
namespace Schema
|
||||
namespace SchemaNs
|
||||
{
|
||||
class SchemaBuilder;
|
||||
}
|
||||
@@ -45,9 +45,9 @@ namespace Schema
|
||||
/*! QueryProcessor alias. */
|
||||
using QueryProcessor = Query::Processors::Processor;
|
||||
/*! SchemaBuilder alias. */
|
||||
using SchemaBuilder = Schema::SchemaBuilder;
|
||||
using SchemaBuilder = SchemaNs::SchemaBuilder;
|
||||
/*! SchemaGrammar alias. */
|
||||
using SchemaGrammar = Schema::Grammars::SchemaGrammar;
|
||||
using SchemaGrammar = SchemaNs::Grammars::SchemaGrammar;
|
||||
|
||||
/*! Database connection base class.
|
||||
TinyORM's DatabaseConnection never physically connects to the database after
|
||||
@@ -162,6 +162,9 @@ namespace Schema
|
||||
/*! Check database connection and show warnings when the state changed. */
|
||||
virtual bool pingDatabase();
|
||||
|
||||
/*! Returns the database driver used to access the database connection. */
|
||||
QSqlDriver *driver();
|
||||
|
||||
/*! Reconnect to the database (doesn't create physical connection, only refreshs
|
||||
a connection resolver). */
|
||||
void reconnect() const;
|
||||
|
||||
@@ -121,6 +121,9 @@ namespace Query
|
||||
/*! Check database connection and show warnings when the state changed. */
|
||||
bool pingDatabase(const QString &connection = "");
|
||||
|
||||
/*! Returns the database driver used to access the database connection. */
|
||||
QSqlDriver *driver(const QString &connection = "");
|
||||
|
||||
/* DatabaseManager */
|
||||
/*! Obtain a shared pointer to the DatabaseManager. */
|
||||
static std::shared_ptr<DatabaseManager> instance();
|
||||
|
||||
@@ -165,6 +165,9 @@ namespace Orm
|
||||
/*! Check database connection and show warnings when the state changed. */
|
||||
static bool pingDatabase(const QString &connection = "");
|
||||
|
||||
/*! Returns the database driver used to access the database connection. */
|
||||
static QSqlDriver *driver(const QString &connection = "");
|
||||
|
||||
/* Queries execution time counter */
|
||||
/*! Determine whether we're counting queries execution time. */
|
||||
static bool
|
||||
|
||||
@@ -61,6 +61,22 @@ namespace Query
|
||||
concept QStringConcept = std::convertible_to<T, const QString &> ||
|
||||
std::convertible_to<T, QString>;
|
||||
|
||||
/*! Type for the database column. */
|
||||
using Column = std::variant<QString, Query::Expression>;
|
||||
|
||||
/*! QString container concept (QStringList or QVector<QString>). */
|
||||
template<typename T>
|
||||
concept ColumnContainer = std::convertible_to<T, const QStringList &> ||
|
||||
std::convertible_to<T, const QVector<QString> &> ||
|
||||
std::convertible_to<T, const QVector<Column> &>;
|
||||
|
||||
// CUR concepts, check if const QString & vs QString in convertible_to<> makes sense silverqx
|
||||
/*! Concept for delimiter for joining containers. */
|
||||
template<typename T>
|
||||
concept DelimiterConcept = std::convertible_to<T, const QString &> ||
|
||||
std::convertible_to<T, QString> ||
|
||||
std::convertible_to<T, QChar>;
|
||||
|
||||
} // namespace Orm
|
||||
|
||||
TINYORM_END_COMMON_NAMESPACE
|
||||
|
||||
140
include/orm/schema.hpp
Normal file
140
include/orm/schema.hpp
Normal file
@@ -0,0 +1,140 @@
|
||||
#pragma once
|
||||
#ifndef ORM_SCHEMA_HPP
|
||||
#define ORM_SCHEMA_HPP
|
||||
|
||||
#include "orm/macros/systemheader.hpp"
|
||||
TINY_SYSTEM_HEADER
|
||||
|
||||
#include "orm/databasemanager.hpp"
|
||||
|
||||
TINYORM_BEGIN_COMMON_NAMESPACE
|
||||
|
||||
namespace Orm
|
||||
{
|
||||
|
||||
/*! Facade class for the Schema builder. */
|
||||
class SHAREDLIB_EXPORT Schema final
|
||||
{
|
||||
Q_DISABLE_COPY(Schema)
|
||||
|
||||
// To access m_schemaBuildersCache
|
||||
friend bool DatabaseManager::removeConnection(const QString &name);
|
||||
|
||||
/*! Alias for the Blueprint. */
|
||||
using Blueprint = SchemaNs::Blueprint;
|
||||
|
||||
public:
|
||||
/*! Deleted default constructor, this is a pure library class. */
|
||||
Schema() = delete;
|
||||
/*! Deleted destructor. */
|
||||
~Schema() = delete;
|
||||
|
||||
/* Proxy methods to the SchemaBuilder */
|
||||
/*! Create a database in the schema. */
|
||||
static QSqlQuery createDatabase(const QString &name,
|
||||
const QString &connection = "");
|
||||
/*! Drop a database from the schema if the database exists. */
|
||||
static QSqlQuery dropDatabaseIfExists(const QString &name,
|
||||
const QString &connection = "");
|
||||
|
||||
/*! Create a new table on the schema. */
|
||||
static void create(const QString &table,
|
||||
const std::function<void(Blueprint &)> &callback,
|
||||
const QString &connection = "");
|
||||
/*! Modify a table on the schema. */
|
||||
static void table(const QString &table,
|
||||
const std::function<void(Blueprint &)> &callback,
|
||||
const QString &connection = "");
|
||||
/*! Drop a table from the schema. */
|
||||
static void drop(const QString &table,
|
||||
const QString &connection = "");
|
||||
/*! Drop a table from the schema if it exists. */
|
||||
static void dropIfExists(const QString &table,
|
||||
const QString &connection = "");
|
||||
|
||||
/*! Rename a table on the schema. */
|
||||
static void rename(const QString &from, const QString &to,
|
||||
const QString &connection = "");
|
||||
|
||||
/*! Drop columns from a table schema. */
|
||||
static void dropColumns(const QString &table, const QVector<QString> &columns,
|
||||
const QString &connection = "");
|
||||
/*! Drop columns from a table schema. */
|
||||
template<QStringConcept ...Args>
|
||||
static void dropColumns(const QString &table, Args &&...columns);
|
||||
/*! Drop one column from a table schema. */
|
||||
static void dropColumn(const QString &table, const QString &column,
|
||||
const QString &connection = "");
|
||||
|
||||
/*! Rename the given column on the schema. */
|
||||
static void renameColumn(const QString &table, const QString &from,
|
||||
const QString &to, const QString &connection = "");
|
||||
|
||||
/*! Drop all tables from the database. */
|
||||
static void dropAllTables(const QString &connection = "");
|
||||
/*! Drop all views from the database. */
|
||||
static void dropAllViews(const QString &connection = "");
|
||||
/*! Drop all types from the database. */
|
||||
static void dropAllTypes(const QString &connection = "");
|
||||
|
||||
/*! Get all of the table names for the database. */
|
||||
static QSqlQuery getAllTables(const QString &connection = "");
|
||||
/*! Get all of the view names for the database. */
|
||||
static QSqlQuery getAllViews(const QString &connection = "");
|
||||
|
||||
/*! Enable foreign key constraints. */
|
||||
static QSqlQuery enableForeignKeyConstraints(const QString &connection = "");
|
||||
/*! Disable foreign key constraints. */
|
||||
static QSqlQuery disableForeignKeyConstraints(const QString &connection = "");
|
||||
|
||||
/*! Get the column listing for a given table. */
|
||||
static QStringList getColumnListing(const QString &table,
|
||||
const QString &connection = "");
|
||||
|
||||
/*! Determine if the given table exists. */
|
||||
static bool hasTable(const QString &table, const QString &connection = "");
|
||||
/*! Determine if the given table has a given column. */
|
||||
static bool hasColumn(const QString &table, const QString &column,
|
||||
const QString &connection = "");
|
||||
/*! Determine if the given table has given columns. */
|
||||
static bool hasColumns(const QString &table, const QVector<QString> &columns,
|
||||
const QString &connection = "");
|
||||
|
||||
/* Schema */
|
||||
/*! Get a schema builder instance for the default connection. */
|
||||
static SchemaBuilder &connection(const QString &name = "");
|
||||
/*! Get a schema builder instance for a connection. (alias for the connection()
|
||||
method). */
|
||||
static SchemaBuilder &on(const QString &name);
|
||||
|
||||
/* Others */
|
||||
/*! Set the default string length for migrations. */
|
||||
static void defaultStringLength(int length);
|
||||
|
||||
private:
|
||||
/*! Alias for the schema builder. */
|
||||
using SchemaBuilder = SchemaNs::SchemaBuilder;
|
||||
|
||||
/*! Get a reference to the SchemaBuilder. */
|
||||
static SchemaBuilder &schemaBuilder(const QString &connection = "");
|
||||
/*! Get a reference to the DatabaseManager. */
|
||||
static DatabaseManager &manager();
|
||||
|
||||
/*! Schema builders cache by connection name. */
|
||||
static std::unordered_map<Connectors::ConnectionName,
|
||||
std::unique_ptr<SchemaBuilder>> m_schemaBuildersCache;
|
||||
/*! Pointer to the DatabaseManager. */
|
||||
static std::shared_ptr<DatabaseManager> m_manager;
|
||||
};
|
||||
|
||||
template<QStringConcept ...Args>
|
||||
void Schema::dropColumns(const QString &table, Args &&...columns)
|
||||
{
|
||||
dropColumns(table, {std::forward<Args>(columns)...});
|
||||
}
|
||||
|
||||
} // namespace Orm
|
||||
|
||||
TINYORM_END_COMMON_NAMESPACE
|
||||
|
||||
#endif // ORM_SCHEMA_HPP
|
||||
690
include/orm/schema/blueprint.hpp
Normal file
690
include/orm/schema/blueprint.hpp
Normal file
@@ -0,0 +1,690 @@
|
||||
#pragma once
|
||||
#ifndef ORM_SCHEMA_BLUEPRINT_HPP
|
||||
#define ORM_SCHEMA_BLUEPRINT_HPP
|
||||
|
||||
#include "orm/macros/systemheader.hpp"
|
||||
TINY_SYSTEM_HEADER
|
||||
|
||||
#include "orm/ormconcepts.hpp"
|
||||
#include "orm/schema/foreignidcolumndefinitionreference.hpp"
|
||||
#include "orm/schema/schemaconstants.hpp"
|
||||
#ifndef TINYORM_DISABLE_ORM
|
||||
# include "orm/tiny/tinytypes.hpp"
|
||||
#endif
|
||||
|
||||
TINYORM_BEGIN_COMMON_NAMESPACE
|
||||
|
||||
namespace Orm
|
||||
{
|
||||
class DatabaseConnection;
|
||||
|
||||
namespace SchemaNs
|
||||
{
|
||||
namespace Grammars
|
||||
{
|
||||
class SchemaGrammar;
|
||||
}
|
||||
|
||||
/*! Table blueprint for the schema grammar. */
|
||||
class SHAREDLIB_EXPORT Blueprint
|
||||
{
|
||||
Q_DISABLE_COPY(Blueprint)
|
||||
|
||||
/*! Alias for the Query::Expression. */
|
||||
using Expression = Query::Expression;
|
||||
/*! Alias for the SchemaGrammar. */
|
||||
using SchemaGrammar = Grammars::SchemaGrammar;
|
||||
|
||||
public:
|
||||
/*! Constructor. */
|
||||
explicit Blueprint(QString table,
|
||||
const std::function<void(Blueprint &)> &callback = nullptr,
|
||||
QString &&prefix = "");
|
||||
/*! Default destructor. */
|
||||
inline ~Blueprint() = default;
|
||||
|
||||
/*! Execute the blueprint against the database. */
|
||||
void build(DatabaseConnection &connection, const SchemaGrammar &grammar);
|
||||
/*! Get the raw SQL statements for the blueprint. */
|
||||
QVector<QString>
|
||||
toSql(const DatabaseConnection &connection, const SchemaGrammar &grammar);
|
||||
|
||||
/*! Indicate that the table needs to be created. */
|
||||
ColumnDefinitionReference<> create();
|
||||
/*! Add the columns from the callback after the given column. */
|
||||
void after(const QString &column,
|
||||
const std::function<void(Blueprint &)> &callback);
|
||||
/*! Indicate that the table should be dropped. */
|
||||
ColumnDefinitionReference<> drop();
|
||||
/*! Indicate that the table should be dropped if it exists. */
|
||||
ColumnDefinitionReference<> dropIfExists();
|
||||
|
||||
/*! Indicate that the given columns should be dropped. */
|
||||
ColumnDefinitionReference<> dropColumns(const QVector<QString> &columns);
|
||||
/*! Indicate that the given columns should be dropped. */
|
||||
template<QStringConcept ...Args>
|
||||
ColumnDefinitionReference<> dropColumns(Args &&...columns);
|
||||
/*! Indicate that the given columns should be dropped. */
|
||||
ColumnDefinitionReference<> dropColumn(const QString &column);
|
||||
|
||||
/*! Indicate that the timestamp columns should be dropped. */
|
||||
void dropTimestamps();
|
||||
/*! Indicate that the timestamp columns should be dropped. */
|
||||
inline void dropTimestampsTz();
|
||||
/*! Indicate that the remember token column should be dropped. */
|
||||
inline void dropRememberToken();
|
||||
|
||||
/*! Rename the table to a given name. */
|
||||
ColumnDefinitionReference<> rename(const QString &to);
|
||||
|
||||
/*! Indicate that the given columns should be renamed. */
|
||||
ColumnDefinitionReference<> renameColumn(const QString &from, const QString &to);
|
||||
|
||||
/*! Specify the primary key(s) for the table. */
|
||||
ColumnDefinitionReference<>
|
||||
primary(const QVector<QString> &columns, const QString &name = "",
|
||||
const QString &algorithm = "");
|
||||
/*! Specify the primary key(s) for the table. */
|
||||
template<typename = void>
|
||||
ColumnDefinitionReference<>
|
||||
primary(const QString &column, const QString &name = "",
|
||||
const QString &algorithm = "");
|
||||
/*! Specify a unique index for the table. */
|
||||
ColumnDefinitionReference<>
|
||||
unique(const QVector<QString> &columns, const QString &name = "",
|
||||
const QString &algorithm = "");
|
||||
/*! Specify a unique index for the table. */
|
||||
template<typename = void>
|
||||
ColumnDefinitionReference<>
|
||||
unique(const QString &column, const QString &name = "",
|
||||
const QString &algorithm = "");
|
||||
/*! Specify an index for the table. */
|
||||
ColumnDefinitionReference<>
|
||||
index(const QVector<QString> &columns, const QString &name = "",
|
||||
const QString &algorithm = "");
|
||||
/*! Specify an index for the table. */
|
||||
template<typename = void>
|
||||
ColumnDefinitionReference<>
|
||||
index(const QString &column, const QString &name = "",
|
||||
const QString &algorithm = "");
|
||||
/*! Specify an fulltext for the table. */
|
||||
ColumnDefinitionReference<>
|
||||
fullText(const QVector<QString> &columns, const QString &name = "",
|
||||
const QString &algorithm = "");
|
||||
/*! Specify an fulltext for the table. */
|
||||
template<typename = void>
|
||||
ColumnDefinitionReference<>
|
||||
fullText(const QString &column, const QString &name = "",
|
||||
const QString &algorithm = "");
|
||||
/*! Specify a spatial index for the table. */
|
||||
ColumnDefinitionReference<>
|
||||
spatialIndex(const QVector<QString> &columns, const QString &name = "");
|
||||
/*! Specify a spatial index for the table. */
|
||||
template<typename = void>
|
||||
ColumnDefinitionReference<>
|
||||
spatialIndex(const QString &column, const QString &name = "");
|
||||
/*! Specify a raw index for the table. */
|
||||
ColumnDefinitionReference<>
|
||||
rawIndex(const Expression &expression, const QString &name);
|
||||
/*! Specify a foreign key for the table. */
|
||||
ForeignKeyDefinitionReference
|
||||
foreign(const QVector<QString> &columns, const QString &name = "");
|
||||
/*! Specify a foreign key for the table. */
|
||||
template<typename = void>
|
||||
ForeignKeyDefinitionReference
|
||||
foreign(const QString &column, const QString &name = "");
|
||||
|
||||
/*! Drop primary key by the given column names. */
|
||||
ColumnDefinitionReference<> dropPrimary(const QVector<QString> &columns = {});
|
||||
/*! Drop unique key by the given column names. */
|
||||
ColumnDefinitionReference<> dropUnique(const QVector<QString> &columns);
|
||||
/*! Drop index by the given column names. */
|
||||
ColumnDefinitionReference<> dropIndex(const QVector<QString> &columns);
|
||||
/*! Drop fulltext index by the given column names. */
|
||||
ColumnDefinitionReference<> dropFullText(const QVector<QString> &columns);
|
||||
/*! Drop spatial index by the given column names. */
|
||||
ColumnDefinitionReference<> dropSpatialIndex(const QVector<QString> &columns);
|
||||
/*! Drop foreign key by the given column names. */
|
||||
ColumnDefinitionReference<> dropForeign(const QVector<QString> &columns);
|
||||
/*! Drop a column and foreign key by the given column name. */
|
||||
ColumnDefinitionReference<> dropConstrainedForeignId(const QString &column);
|
||||
|
||||
/*! Drop primary key by the given index name. */
|
||||
template<typename = void>
|
||||
ColumnDefinitionReference<> dropPrimary(const QString &index = "");
|
||||
/*! Drop unique key by the given index name. */
|
||||
template<typename = void>
|
||||
ColumnDefinitionReference<> dropUnique(const QString &index);
|
||||
/*! Drop index by the given index name. */
|
||||
template<typename = void>
|
||||
ColumnDefinitionReference<> dropIndex(const QString &index);
|
||||
/*! Drop fulltext index by the given index name. */
|
||||
template<typename = void>
|
||||
ColumnDefinitionReference<> dropFullText(const QString &index);
|
||||
/*! Drop spatial index by the given index name. */
|
||||
template<typename = void>
|
||||
ColumnDefinitionReference<> dropSpatialIndex(const QString &index);
|
||||
/*! Drop foreign key by the given index name. */
|
||||
template<typename = void>
|
||||
ColumnDefinitionReference<> dropForeign(const QString &index);
|
||||
|
||||
/*! Indicate that the given indexes should be renamed. */
|
||||
ColumnDefinitionReference<> renameIndex(const QString &from, const QString &to);
|
||||
|
||||
/*! Create a new auto-incrementing big integer (8-byte) column on the table. */
|
||||
inline ColumnDefinitionReference<> id(const QString &column = Orm::Constants::ID);
|
||||
|
||||
/*! Create a new unsigned big integer (8-byte) column on the table. */
|
||||
ForeignIdColumnDefinitionReference foreignId(const QString &column);
|
||||
#ifndef TINYORM_DISABLE_ORM
|
||||
/*! Create a foreign ID column for the given model. */
|
||||
template<Tiny::ModelConcept Model>
|
||||
ForeignIdColumnDefinitionReference foreignIdFor(const Model &model,
|
||||
const QString &column = "");
|
||||
#endif
|
||||
/*! Create a new UUID column on the table with a foreign key constraint. */
|
||||
ForeignIdColumnDefinitionReference foreignUuid(const QString &column);
|
||||
|
||||
/*! Create a new auto-incrementing integer (4-byte) column on the table. */
|
||||
inline ColumnDefinitionReference<> increments(const QString &column);
|
||||
/*! Create a new auto-incrementing integer (4-byte) column on the table. */
|
||||
inline ColumnDefinitionReference<> integerIncrements(const QString &column);
|
||||
/*! Create a new auto-incrementing tiny integer (1-byte) column on the table. */
|
||||
inline ColumnDefinitionReference<> tinyIncrements(const QString &column);
|
||||
/*! Create a new auto-incrementing small integer (2-byte) column on the table. */
|
||||
inline ColumnDefinitionReference<> smallIncrements(const QString &column);
|
||||
/*! Create a new auto-incrementing medium integer (3-byte) column on the table. */
|
||||
inline ColumnDefinitionReference<> mediumIncrements(const QString &column);
|
||||
/*! Create a new auto-incrementing big integer (8-byte) column on the table. */
|
||||
inline ColumnDefinitionReference<> bigIncrements(const QString &column);
|
||||
|
||||
/*! Create a new integer (4-byte) column on the table. */
|
||||
ColumnDefinitionReference<>
|
||||
integer(const QString &column, bool autoIncrement = false,
|
||||
bool isUnsigned = false);
|
||||
/*! Create a new tiny integer (1-byte) column on the table. */
|
||||
ColumnDefinitionReference<>
|
||||
tinyInteger(const QString &column, bool autoIncrement = false,
|
||||
bool isUnsigned = false);
|
||||
/*! Create a new small integer (2-byte) column on the table. */
|
||||
ColumnDefinitionReference<>
|
||||
smallInteger(const QString &column, bool autoIncrement = false,
|
||||
bool isUnsigned = false);
|
||||
/*! Create a new medium integer (3-byte) column on the table. */
|
||||
ColumnDefinitionReference<>
|
||||
mediumInteger(const QString &column, bool autoIncrement = false,
|
||||
bool isUnsigned = false);
|
||||
/*! Create a new unsigned big integer (8-byte) column on the table. */
|
||||
ColumnDefinitionReference<>
|
||||
bigInteger(const QString &column, bool autoIncrement = false,
|
||||
bool isUnsigned = false);
|
||||
|
||||
/*! Create a new unsigned integer (4-byte) column on the table. */
|
||||
inline ColumnDefinitionReference<>
|
||||
unsignedInteger(const QString &column, bool autoIncrement = false);
|
||||
/*! Create a new unsigned tiny integer (1-byte) column on the table. */
|
||||
inline ColumnDefinitionReference<>
|
||||
unsignedTinyInteger(const QString &column, bool autoIncrement = false);
|
||||
/*! Create a new unsigned small integer (2-byte) column on the table. */
|
||||
inline ColumnDefinitionReference<>
|
||||
unsignedSmallInteger(const QString &column, bool autoIncrement = false);
|
||||
/*! Create a new unsigned medium integer (3-byte) column on the table. */
|
||||
inline ColumnDefinitionReference<>
|
||||
unsignedMediumInteger(const QString &column, bool autoIncrement = false);
|
||||
/*! Create a new unsigned big integer (8-byte) column on the table. */
|
||||
inline ColumnDefinitionReference<>
|
||||
unsignedBigInteger(const QString &column, bool autoIncrement = false);
|
||||
|
||||
/*! Create a new char column on the table. */
|
||||
ColumnDefinitionReference<>
|
||||
Char(const QString &column, int length = DefaultStringLength);
|
||||
|
||||
/*! Create a new string column on the table. */
|
||||
ColumnDefinitionReference<> string(const QString &column,
|
||||
int length = DefaultStringLength);
|
||||
/*! Create a new tiny text column on the table. */
|
||||
ColumnDefinitionReference<> tinyText(const QString &column);
|
||||
/*! Create a new text column on the table. */
|
||||
ColumnDefinitionReference<> text(const QString &column);
|
||||
/*! Create a new medium text column on the table. */
|
||||
ColumnDefinitionReference<> mediumText(const QString &column);
|
||||
/*! Create a new long text column on the table. */
|
||||
ColumnDefinitionReference<> longText(const QString &column);
|
||||
|
||||
/*! Create a new float column on the table. */
|
||||
ColumnDefinitionReference<>
|
||||
Float(const QString &column, std::optional<int> total = 8,
|
||||
std::optional<int> places = 2, bool isUnsigned = false);
|
||||
/*! Create a new double column on the table. */
|
||||
ColumnDefinitionReference<>
|
||||
Double(const QString &column, std::optional<int> total = std::nullopt,
|
||||
std::optional<int> places = std::nullopt, bool isUnsigned = false);
|
||||
/*! Create a new decimal column on the table. */
|
||||
ColumnDefinitionReference<>
|
||||
decimal(const QString &column, std::optional<int> total = 8,
|
||||
std::optional<int> places = 2, bool isUnsigned = false);
|
||||
|
||||
/*! Create a new unsigned float column on the table. */
|
||||
inline ColumnDefinitionReference<>
|
||||
unsignedFloat(const QString &column, std::optional<int> total = 8,
|
||||
std::optional<int> places = 2);
|
||||
/*! Create a new unsigned double column on the table. */
|
||||
inline ColumnDefinitionReference<>
|
||||
unsignedDouble(const QString &column, std::optional<int> total = std::nullopt,
|
||||
std::optional<int> places = std::nullopt);
|
||||
/*! Create a new unsigned decimal column on the table. */
|
||||
inline ColumnDefinitionReference<>
|
||||
unsignedDecimal(const QString &column, std::optional<int> total = 8,
|
||||
std::optional<int> places = 2);
|
||||
|
||||
/*! Create a new boolean column on the table. */
|
||||
ColumnDefinitionReference<> boolean(const QString &column);
|
||||
|
||||
/*! Create a new enum column on the table. */
|
||||
ColumnDefinitionReference<> Enum(const QString &column,
|
||||
const QVector<QString> &allowed);
|
||||
/*! Create a new set column on the table. */
|
||||
ColumnDefinitionReference<> set(const QString &column,
|
||||
const QVector<QString> &allowed);
|
||||
|
||||
/*! Create a new json column on the table. */
|
||||
ColumnDefinitionReference<> json(const QString &column);
|
||||
/*! Create a new jsonb column on the table. */
|
||||
ColumnDefinitionReference<> jsonb(const QString &column);
|
||||
|
||||
/*! Create a new date column on the table. */
|
||||
ColumnDefinitionReference<> date(const QString &column);
|
||||
/*! Create a new date-time column on the table. */
|
||||
ColumnDefinitionReference<> dateTime(const QString &column, int precision = 0);
|
||||
/*! Create a new date-time column (with time zone) on the table. */
|
||||
ColumnDefinitionReference<> dateTimeTz(const QString &column, int precision = 0);
|
||||
|
||||
/*! Create a new time column on the table. */
|
||||
ColumnDefinitionReference<> time(const QString &column, int precision = 0);
|
||||
/*! Create a new time column (with time zone) on the table. */
|
||||
ColumnDefinitionReference<> timeTz(const QString &column, int precision = 0);
|
||||
|
||||
/*! Create a new timestamp column on the table. */
|
||||
ColumnDefinitionReference<> timestamp(const QString &column, int precision = 0);
|
||||
/*! Create a new timestamp (with time zone) column on the table. */
|
||||
ColumnDefinitionReference<> timestampTz(const QString &column, int precision = 0);
|
||||
|
||||
/*! Add nullable creation and update timestamps to the table. */
|
||||
void timestamps(int precision = 0);
|
||||
/*! Add creation and update timestampTz columns to the table. */
|
||||
void timestampsTz(int precision = 0);
|
||||
|
||||
/*! Create a new year column on the table. */
|
||||
ColumnDefinitionReference<> year(const QString &column);
|
||||
|
||||
/*! Create a new binary column on the table. */
|
||||
ColumnDefinitionReference<> binary(const QString &column);
|
||||
|
||||
/*! Create a new uuid column on the table. */
|
||||
ColumnDefinitionReference<>
|
||||
uuid(const QString &column = QStringLiteral("uuid"));
|
||||
|
||||
/*! Create a new IP address column on the table. */
|
||||
ColumnDefinitionReference<>
|
||||
ipAddress(const QString &column = QStringLiteral("ip_address"));
|
||||
/*! Create a new MAC address column on the table. */
|
||||
ColumnDefinitionReference<>
|
||||
macAddress(const QString &column = QStringLiteral("mac_address"));
|
||||
|
||||
/*! Create a new geometry column on the table. */
|
||||
ColumnDefinitionReference<> geometry(const QString &column);
|
||||
/*! Create a new point column on the table. */
|
||||
ColumnDefinitionReference<> point(const QString &column,
|
||||
std::optional<quint32> srid = std::nullopt);
|
||||
/*! Create a new linestring column on the table. */
|
||||
ColumnDefinitionReference<> lineString(const QString &column);
|
||||
/*! Create a new polygon column on the table. */
|
||||
ColumnDefinitionReference<> polygon(const QString &column);
|
||||
/*! Create a new geometrycollection column on the table. */
|
||||
ColumnDefinitionReference<> geometryCollection(const QString &column);
|
||||
/*! Create a new multipoint column on the table. */
|
||||
ColumnDefinitionReference<> multiPoint(const QString &column);
|
||||
/*! Create a new multilinestring column on the table. */
|
||||
ColumnDefinitionReference<> multiLineString(const QString &column);
|
||||
/*! Create a new multipolygon column on the table. */
|
||||
ColumnDefinitionReference<> multiPolygon(const QString &column);
|
||||
/*! Create a new multipolygon column on the table. */
|
||||
ColumnDefinitionReference<> multiPolygonZ(const QString &column);
|
||||
|
||||
/*! Create a new generated, computed column on the table. */
|
||||
ColumnDefinitionReference<> computed(const QString &column,
|
||||
const QString &expression);
|
||||
|
||||
/*! Adds the `remember_token` column to the table. */
|
||||
ColumnDefinitionReference<> rememberToken();
|
||||
|
||||
/*! Add a new column to the blueprint. */
|
||||
ColumnDefinitionReference<> addColumn(ColumnType type, const QString &name,
|
||||
ColumnDefinition &¶meters = {});
|
||||
|
||||
/* Others */
|
||||
/*! Get the columns on the blueprint that should be added. */
|
||||
QVector<ColumnDefinition> getAddedColumns() const;
|
||||
/*! Get the columns on the blueprint that should be changed. */
|
||||
QVector<ColumnDefinition> getChangedColumns() const;
|
||||
|
||||
/*! Determine if the blueprint has auto-increment columns. */
|
||||
bool hasAutoIncrementColumn() const;
|
||||
/*! Get the auto-increment column starting values. */
|
||||
QVector<AutoIncrementColumnValue> autoIncrementStartingValues() const;
|
||||
/*! Determine if the blueprint has a create command. */
|
||||
bool creating() const;
|
||||
|
||||
/*! Remove a column from the schema blueprint. */
|
||||
Blueprint &removeColumn(const QString &name);
|
||||
|
||||
/* Getters */
|
||||
/*! Get the table the blueprint describes. */
|
||||
inline const QString &getTable() const noexcept;
|
||||
/*! Get the columns on the blueprint. */
|
||||
inline const QVector<ColumnDefinition> &getColumns() const noexcept;
|
||||
/*! Get the commands on the blueprint. */
|
||||
inline const QVector<ColumnDefinition> &getCommands() const noexcept;
|
||||
/*! Determine whether the blueprint describes temporary table. */
|
||||
inline bool isTemporary() const noexcept;
|
||||
|
||||
/* Others */
|
||||
/*! Indicate that the table needs to be temporary. */
|
||||
inline void temporary() noexcept;
|
||||
|
||||
/*! Set the default string length for migrations. */
|
||||
static void defaultStringLength(int length) noexcept;
|
||||
|
||||
// CUR schema, should be T_THREAD_LOCAL? cant be now, thread_local can not be part of dll interface silverqx
|
||||
/*! The default string length for migrations. */
|
||||
static int DefaultStringLength;
|
||||
|
||||
/*! The storage engine that should be used for the table. */
|
||||
QString engine;
|
||||
/*! The default character set that should be used for the table. */
|
||||
QString charset;
|
||||
/*! The collation that should be used for the table. */
|
||||
QString collation;
|
||||
|
||||
protected:
|
||||
/*! Expose column types. */
|
||||
// using enum ColumnType;
|
||||
|
||||
/*! Add a new column definition to the blueprint. */
|
||||
ColumnDefinitionReference<> addColumnDefinition(ColumnDefinition &&definition);
|
||||
|
||||
/*! Add a new command to the blueprint. */
|
||||
ColumnDefinitionReference<> addCommand(const QString &name,
|
||||
ColumnDefinition &¶meters = {});
|
||||
/*! Create a new Fluent command.. */
|
||||
ColumnDefinition createCommand(const QString &name,
|
||||
ColumnDefinition &¶meters = {});
|
||||
|
||||
/*! Add the commands that are implied by the blueprint's state. */
|
||||
void addImpliedCommands(const SchemaGrammar &grammar);
|
||||
/*! Add the index commands fluently specified on columns. */
|
||||
void addFluentIndexes();
|
||||
|
||||
/*! Add a new index command to the blueprint. */
|
||||
ColumnDefinitionReference<>
|
||||
indexCommand(const QString &type, const QVector<QString> &columns,
|
||||
const QString &indexName, const QString &algorithm = "");
|
||||
/*! Create a new drop index command on the blueprint. */
|
||||
ColumnDefinitionReference<>
|
||||
dropIndexCommand(const QString &command, const QString &type,
|
||||
const QVector<QString> &columns);
|
||||
/*! Create a new drop index command on the blueprint. */
|
||||
ColumnDefinitionReference<>
|
||||
dropIndexCommand(const QString &command, const QString &index);
|
||||
|
||||
/*! Create a default index name for the table. */
|
||||
QString createIndexName(const QString &type,
|
||||
const QVector<QString> &columns) const;
|
||||
|
||||
/*! The table the blueprint describes. */
|
||||
QString m_table;
|
||||
/*! The prefix of the table. */
|
||||
QString m_prefix;
|
||||
|
||||
/*! The columns that should be added to the table. */
|
||||
QVector<ColumnDefinition> m_columns;
|
||||
/*! The commands that should be run for the table. */
|
||||
QVector<ColumnDefinition> m_commands;
|
||||
|
||||
/*! Whether to make the table temporary. */
|
||||
bool m_temporary = false;
|
||||
/*! The column to add new columns after. */
|
||||
QString m_after;
|
||||
};
|
||||
|
||||
/* public */
|
||||
|
||||
#ifndef TINYORM_DISABLE_ORM
|
||||
template<Tiny::ModelConcept Model>
|
||||
ForeignIdColumnDefinitionReference
|
||||
Blueprint::foreignIdFor(const Model &model, const QString &column)
|
||||
{
|
||||
const auto column_ = column.isEmpty() ? model.getForeignKey() : column;
|
||||
|
||||
// FEATURE dilemma primarykey, Model::KeyType vs QVariant silverqx
|
||||
return std::is_integral_v<typename Model::KeyType> && model.getIncrementing()
|
||||
? foreignId(column_)
|
||||
: foreignUuid(column_);
|
||||
}
|
||||
#endif
|
||||
|
||||
template<QStringConcept ...Args>
|
||||
ColumnDefinitionReference<> Blueprint::dropColumns(Args &&...columns)
|
||||
{
|
||||
return dropColumns(QVector<QString> {std::forward<Args>(columns)...});
|
||||
}
|
||||
|
||||
void Blueprint::dropTimestampsTz()
|
||||
{
|
||||
dropTimestamps();
|
||||
}
|
||||
|
||||
void Blueprint::dropRememberToken()
|
||||
{
|
||||
dropColumns({QStringLiteral("remember_token")});
|
||||
}
|
||||
|
||||
template<typename>
|
||||
ColumnDefinitionReference<>
|
||||
Blueprint::primary(const QString &column, const QString &name,
|
||||
const QString &algorithm)
|
||||
{
|
||||
return primary(QVector<QString> {column}, name, algorithm);
|
||||
}
|
||||
|
||||
template<typename>
|
||||
ColumnDefinitionReference<>
|
||||
Blueprint::unique(const QString &column, const QString &name,
|
||||
const QString &algorithm)
|
||||
{
|
||||
return unique(QVector<QString> {column}, name, algorithm);
|
||||
}
|
||||
|
||||
template<typename>
|
||||
ColumnDefinitionReference<>
|
||||
Blueprint::index(const QString &column, const QString &name,
|
||||
const QString &algorithm)
|
||||
{
|
||||
return index(QVector<QString> {column}, name, algorithm);
|
||||
}
|
||||
|
||||
template<typename>
|
||||
ColumnDefinitionReference<>
|
||||
Blueprint::fullText(const QString &column, const QString &name,
|
||||
const QString &algorithm)
|
||||
{
|
||||
return fullText(QVector<QString> {column}, name, algorithm);
|
||||
}
|
||||
|
||||
template<typename>
|
||||
ColumnDefinitionReference<>
|
||||
Blueprint::spatialIndex(const QString &column, const QString &name)
|
||||
{
|
||||
return spatialIndex(QVector<QString> {column}, name);
|
||||
}
|
||||
|
||||
template<typename>
|
||||
ForeignKeyDefinitionReference
|
||||
Blueprint::foreign(const QString &column, const QString &name)
|
||||
{
|
||||
return foreign(QVector<QString> {column}, name);
|
||||
}
|
||||
|
||||
template<typename>
|
||||
ColumnDefinitionReference<> Blueprint::dropPrimary(const QString &index)
|
||||
{
|
||||
return dropIndexCommand(DropPrimary, index);
|
||||
}
|
||||
|
||||
template<typename>
|
||||
ColumnDefinitionReference<> Blueprint::dropUnique(const QString &index)
|
||||
{
|
||||
return dropIndexCommand(DropUnique, index);
|
||||
}
|
||||
|
||||
template<typename>
|
||||
ColumnDefinitionReference<> Blueprint::dropIndex(const QString &index)
|
||||
{
|
||||
return dropIndexCommand(DropIndex, index);
|
||||
}
|
||||
|
||||
template<typename>
|
||||
ColumnDefinitionReference<> Blueprint::dropFullText(const QString &index)
|
||||
{
|
||||
return dropIndexCommand(DropFullText, index);
|
||||
}
|
||||
|
||||
template<typename>
|
||||
ColumnDefinitionReference<> Blueprint::dropSpatialIndex(const QString &index)
|
||||
{
|
||||
return dropIndexCommand(DropSpatialIndex, index);
|
||||
}
|
||||
|
||||
template<typename>
|
||||
ColumnDefinitionReference<> Blueprint::dropForeign(const QString &index)
|
||||
{
|
||||
return dropIndexCommand(DropForeign, index);
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<> Blueprint::id(const QString &column)
|
||||
{
|
||||
return bigIncrements(column);
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<> Blueprint::increments(const QString &column)
|
||||
{
|
||||
return unsignedInteger(column, true);
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<> Blueprint::integerIncrements(const QString &column)
|
||||
{
|
||||
return unsignedInteger(column, true);
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<> Blueprint::tinyIncrements(const QString &column)
|
||||
{
|
||||
return unsignedTinyInteger(column, true);
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<> Blueprint::smallIncrements(const QString &column)
|
||||
{
|
||||
return unsignedSmallInteger(column, true);
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<> Blueprint::mediumIncrements(const QString &column)
|
||||
{
|
||||
return unsignedMediumInteger(column, true);
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<> Blueprint::bigIncrements(const QString &column)
|
||||
{
|
||||
return unsignedBigInteger(column, true);
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<>
|
||||
Blueprint::unsignedInteger(const QString &column, const bool autoIncrement)
|
||||
{
|
||||
return integer(column, autoIncrement, true);
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<>
|
||||
Blueprint::unsignedTinyInteger(const QString &column, const bool autoIncrement)
|
||||
{
|
||||
return tinyInteger(column, autoIncrement, true);
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<>
|
||||
Blueprint::unsignedSmallInteger(const QString &column, const bool autoIncrement)
|
||||
{
|
||||
return smallInteger(column, autoIncrement, true);
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<>
|
||||
Blueprint::unsignedMediumInteger(const QString &column, const bool autoIncrement)
|
||||
{
|
||||
return mediumInteger(column, autoIncrement, true);
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<>
|
||||
Blueprint::unsignedBigInteger(const QString &column, const bool autoIncrement)
|
||||
{
|
||||
return bigInteger(column, autoIncrement, true);
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<>
|
||||
Blueprint::unsignedFloat(const QString &column, const std::optional<int> total,
|
||||
const std::optional<int> places)
|
||||
{
|
||||
return Float(column, total, places, true);
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<>
|
||||
Blueprint::unsignedDouble(const QString &column, const std::optional<int> total,
|
||||
const std::optional<int> places)
|
||||
{
|
||||
return Double(column, total, places, true);
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<>
|
||||
Blueprint::unsignedDecimal(const QString &column, const std::optional<int> total,
|
||||
const std::optional<int> places)
|
||||
{
|
||||
return decimal(column, total, places, true);
|
||||
}
|
||||
|
||||
const QString &Blueprint::getTable() const noexcept
|
||||
{
|
||||
return m_table;
|
||||
}
|
||||
|
||||
const QVector<ColumnDefinition> &Blueprint::getColumns() const noexcept
|
||||
{
|
||||
return m_columns;
|
||||
}
|
||||
|
||||
const QVector<ColumnDefinition> &Blueprint::getCommands() const noexcept
|
||||
{
|
||||
return m_commands;
|
||||
}
|
||||
|
||||
bool Blueprint::isTemporary() const noexcept
|
||||
{
|
||||
return m_temporary;
|
||||
}
|
||||
|
||||
void Blueprint::temporary() noexcept
|
||||
{
|
||||
m_temporary = true;
|
||||
}
|
||||
|
||||
} // namespace SchemaNs
|
||||
} // namespace Orm
|
||||
|
||||
TINYORM_END_COMMON_NAMESPACE
|
||||
|
||||
#endif // ORM_SCHEMA_BLUEPRINT_HPP
|
||||
132
include/orm/schema/columndefinition.hpp
Normal file
132
include/orm/schema/columndefinition.hpp
Normal file
@@ -0,0 +1,132 @@
|
||||
#pragma once
|
||||
#ifndef ORM_SCHEMA_COLUMNDEFINITION_HPP
|
||||
#define ORM_SCHEMA_COLUMNDEFINITION_HPP
|
||||
|
||||
#include "orm/macros/systemheader.hpp"
|
||||
TINY_SYSTEM_HEADER
|
||||
|
||||
#include <QVariant>
|
||||
|
||||
#include "orm/query/expression.hpp"
|
||||
#include "orm/schema/schematypes.hpp"
|
||||
|
||||
TINYORM_BEGIN_COMMON_NAMESPACE
|
||||
|
||||
namespace Orm::SchemaNs
|
||||
{
|
||||
|
||||
/*! Database column definition. */
|
||||
class ColumnDefinition
|
||||
{
|
||||
/*! Type for the database column. */
|
||||
using Column = std::variant<QString, Query::Expression>;
|
||||
|
||||
public:
|
||||
/*! Column type. */
|
||||
ColumnType type;
|
||||
/*! Column name. */
|
||||
QString name;
|
||||
/*! Indicates whether a column will be changed or created. */
|
||||
bool change = false;
|
||||
|
||||
/* Commands */
|
||||
// indexes, and columns also used in dropColumns()
|
||||
/*! Index name. */
|
||||
QString index;
|
||||
/*! Columns for which to create an index. */
|
||||
QVector<Column> columns; // foreign key
|
||||
/*! Algorith to use during index creation. */
|
||||
QString algorithm;
|
||||
|
||||
// rename index
|
||||
/*! Rename index from. */
|
||||
QString from_;
|
||||
/*! Rename index to. */
|
||||
QString to;
|
||||
|
||||
// foreign key
|
||||
/*! Specifies the referenced columns. */
|
||||
QVector<QString> references;
|
||||
/*! Specifies the referenced table. */
|
||||
QString on;
|
||||
/*! Specifies ON DELETE action (cascade/restrict/set null/no action/
|
||||
set default). */
|
||||
QString onDelete;
|
||||
/*! Specifies ON UPDATE action (cascade/restrict/set null/no action/
|
||||
set default). */
|
||||
QString onUpdate;
|
||||
|
||||
/* Internal - used from blueprint */
|
||||
/*! Allowed index values for Enumaration Literals (enum/set). */
|
||||
QVector<QString> allowed;
|
||||
/*! Value for a generated, computed column type (SQL Server). */
|
||||
QString expression;
|
||||
/*! Length of the char or varchar column. */
|
||||
int length = DefaultStringLength;
|
||||
/*! Number of digits after the decimal point for floating-point types. */
|
||||
std::optional<int> places;
|
||||
/*! Determine fractional Seconds in Time Values (MySQL 0-6). */
|
||||
int precision;
|
||||
/* srid max. value should be 2^32-1 as is described here, so unsigned int
|
||||
should be ok:
|
||||
https://dev.mysql.com/doc/refman/8.0/en/spatial-function-argument-handling.html */
|
||||
/*! The spatial reference identifier (SRID) of a geometry identifies the SRS
|
||||
in which the geometry is defined. */
|
||||
std::optional<quint32> srid;
|
||||
/*! Number of digits before the decimal point for floating-point types. */
|
||||
std::optional<int> total;
|
||||
|
||||
/* Indexes */
|
||||
/*! Add an index. */
|
||||
std::variant<std::monostate, QString, bool> index_;
|
||||
/*! Add a primary index. */
|
||||
std::variant<std::monostate, QString, bool> primary;
|
||||
/*! Add a fulltext index. */
|
||||
std::variant<std::monostate, QString, bool> fulltext;
|
||||
/*! Add a spatial index. */
|
||||
std::variant<std::monostate, QString, bool> spatialIndex;
|
||||
/*! Add a unique index. */
|
||||
std::variant<std::monostate, QString, bool> unique;
|
||||
|
||||
/* Column definitions */
|
||||
/*! Determine "after" which column to place a current column (MySQL). */
|
||||
QString after;
|
||||
/*! Specify a character set for the column (MySQL). */
|
||||
QString charset;
|
||||
/*! Specify a collation for the column (MySQL/PostgreSQL/SQL Server). */
|
||||
QString collation;
|
||||
/*! Add a comment to the column (MySQL/PostgreSQL). */
|
||||
QString comment;
|
||||
/*! Specify a "default" value for the column. */
|
||||
QVariant defaultValue;
|
||||
/*! Set the starting value of an auto-incrementing field (MySQL / PostgreSQL). */
|
||||
std::optional<quint64> from;
|
||||
/*! Set the starting value of an auto-incrementing field (MySQL / PostgreSQL). */
|
||||
std::optional<quint64> startingValue;
|
||||
/*! Create a stored generated column (MySQL/PostgreSQL/SQLite). */
|
||||
QString storedAs;
|
||||
/*! Create a virtual generated column (MySQL/PostgreSQL/SQLite). */
|
||||
QString virtualAs;
|
||||
|
||||
// Place boolean data members at the end to avoid excessive padding
|
||||
/*! Determine whether the INTEGER column is auto-increment (primary key). */
|
||||
bool autoIncrement = false;
|
||||
/*! Place the column "first" in the table (MySQL). */
|
||||
bool first = false;
|
||||
/*! Specify that the column should be invisible to "SELECT *" (MySQL). */
|
||||
bool invisible = false;
|
||||
/*! Determine whether the INTEGER column is UNSIGNED (MySQL). */
|
||||
bool isUnsigned = false;
|
||||
/*! Allow NULL values to be inserted into the column. */
|
||||
bool nullable = false;
|
||||
/*! Set the TIMESTAMP column to use CURRENT_TIMESTAMP as default value. */
|
||||
bool useCurrent = false;
|
||||
/*! Set the TIMESTAMP column to use CURRENT_TIMESTAMP when updating (MySQL). */
|
||||
bool useCurrentOnUpdate = false;
|
||||
};
|
||||
|
||||
} // namespace Orm::SchemaNs
|
||||
|
||||
TINYORM_END_COMMON_NAMESPACE
|
||||
|
||||
#endif // ORM_SCHEMA_COLUMNDEFINITION_HPP
|
||||
332
include/orm/schema/columndefinitionreference.hpp
Normal file
332
include/orm/schema/columndefinitionreference.hpp
Normal file
@@ -0,0 +1,332 @@
|
||||
#pragma once
|
||||
#ifndef ORM_SCHEMA_COLUMNDEFINITIONREFERENCE_HPP
|
||||
#define ORM_SCHEMA_COLUMNDEFINITIONREFERENCE_HPP
|
||||
|
||||
#include "orm/macros/systemheader.hpp"
|
||||
TINY_SYSTEM_HEADER
|
||||
|
||||
#include "orm/schema/columndefinition.hpp"
|
||||
|
||||
TINYORM_BEGIN_COMMON_NAMESPACE
|
||||
|
||||
namespace Orm::SchemaNs
|
||||
{
|
||||
|
||||
class ForeignIdColumnDefinitionReference;
|
||||
|
||||
/*! Concept for the column reference return type, based on this template parameter
|
||||
will be decided what type it will be. */
|
||||
template<typename T>
|
||||
concept ColumnReferenceReturn = std::is_void_v<T> ||
|
||||
std::same_as<T, ForeignIdColumnDefinitionReference>;
|
||||
|
||||
/*! Reference class to the ColumnDefinition, provides setters with a nice API
|
||||
for the database column (includes indexes). */
|
||||
template<ColumnReferenceReturn R = void>
|
||||
class ColumnDefinitionReference
|
||||
{
|
||||
// To access m_columnDefinition data member
|
||||
friend ForeignIdColumnDefinitionReference;
|
||||
// To access m_columnDefinition data member
|
||||
friend class ForeignKeyDefinitionReference;
|
||||
|
||||
public:
|
||||
/*! CRTP return type by the passed R template parameter. */
|
||||
using ColumnReferenceType =
|
||||
std::conditional_t<std::is_void_v<R>, ColumnDefinitionReference, R>;
|
||||
|
||||
/*! Constructor. */
|
||||
ColumnDefinitionReference(ColumnDefinition &columnDefinition); // NOLINT(google-explicit-constructor)
|
||||
/*! Default destructor. */
|
||||
inline ~ColumnDefinitionReference() = default;
|
||||
|
||||
/*! Place the column "after" another column (MySQL). */
|
||||
ColumnReferenceType &after(const QString &column);
|
||||
/*! Set INTEGER column as auto-increment (primary key). */
|
||||
ColumnReferenceType &autoIncrement();
|
||||
/*! Specify a character set for the column (MySQL). */
|
||||
ColumnReferenceType &charset(const QString &charset);
|
||||
/*! Specify a collation for the column (MySQL/PostgreSQL/SQL Server). */
|
||||
ColumnReferenceType &collation(const QString &collation);
|
||||
/*! Add a comment to the column (MySQL/PostgreSQL). */
|
||||
ColumnReferenceType &comment(const QString &comment);
|
||||
/*! Specify a "default" value for the column. */
|
||||
ColumnReferenceType &defaultValue(const QVariant &value);
|
||||
/*! Place the column "first" in the table (MySQL). */
|
||||
ColumnReferenceType &first();
|
||||
/*! Set the starting value of an auto-incrementing field (MySQL / PostgreSQL). */
|
||||
ColumnReferenceType &from(int startingValue);
|
||||
/*! Specify that the column should be invisible to "SELECT *" (MySQL). */
|
||||
ColumnReferenceType &invisible();
|
||||
/*! Set the INTEGER column as UNSIGNED (MySQL). */
|
||||
ColumnReferenceType &isUnsigned();
|
||||
/*! Allow NULL values to be inserted into the column. */
|
||||
ColumnReferenceType &nullable(bool value = true);
|
||||
/*! Set the starting value of an auto-incrementing field (MySQL/PostgreSQL). */
|
||||
ColumnReferenceType &startingValue(int startingValue);
|
||||
/*! Create a stored generated column (MySQL/PostgreSQL/SQLite). */
|
||||
ColumnReferenceType &storedAs(const QString &expression);
|
||||
/*! Set the TIMESTAMP column to use CURRENT_TIMESTAMP as default value. */
|
||||
ColumnReferenceType &useCurrent();
|
||||
/*! Set the TIMESTAMP column to use CURRENT_TIMESTAMP when updating (MySQL). */
|
||||
ColumnReferenceType &useCurrentOnUpdate();
|
||||
/*! Create a virtual generated column (MySQL/PostgreSQL/SQLite). */
|
||||
ColumnReferenceType &virtualAs(const QString &expression);
|
||||
|
||||
/*! Add an index. */
|
||||
ColumnReferenceType &index(const QString &indexName = "");
|
||||
/*! Add a primary index. */
|
||||
ColumnReferenceType &primary();
|
||||
/*! Add a fulltext index. */
|
||||
ColumnReferenceType &fulltext(const QString &indexName = "");
|
||||
/*! Add a spatial index. */
|
||||
ColumnReferenceType &spatialIndex(const QString &indexName = "");
|
||||
/*! Add a unique index. */
|
||||
ColumnReferenceType &unique(const QString &indexName = "");
|
||||
|
||||
private:
|
||||
/*! Static cast this to a child's instance type (CRTP). */
|
||||
ColumnReferenceType &columnReference();
|
||||
|
||||
/*! Reference to a column definition. */
|
||||
std::reference_wrapper<ColumnDefinition> m_columnDefinition;
|
||||
};
|
||||
|
||||
/* I had to make this class templated to be able call eg. foreignId().nullable(),
|
||||
be able to call ColumnDefinitionReference methods
|
||||
on the ForeignIdColumnDefinitionReference class.
|
||||
ColumnDefinitionReference methods have to return
|
||||
the ForeignIdColumnDefinitionReference & if 'this' is
|
||||
the ForeignIdColumnDefinitionReference instance.
|
||||
It added a little mess but it was absolutely necessary.
|
||||
I can return ColumnReferenceType & because a real instance is created by
|
||||
Blueprint methods and lives in that fluent call, exception are
|
||||
ForeignKeyDefinitionReference methods, there & can not be returned because
|
||||
a real instance is created inside
|
||||
the ForeignIdColumnDefinitionReference::references() method so returning by
|
||||
a value is necessary (if not then dangling reference occurs and crash happens). */
|
||||
|
||||
/* public */
|
||||
|
||||
template<ColumnReferenceReturn R>
|
||||
ColumnDefinitionReference<R>::ColumnDefinitionReference(
|
||||
ColumnDefinition &columnDefinition
|
||||
)
|
||||
: m_columnDefinition(columnDefinition)
|
||||
{}
|
||||
|
||||
template<ColumnReferenceReturn R>
|
||||
typename ColumnDefinitionReference<R>::ColumnReferenceType &
|
||||
ColumnDefinitionReference<R>::after(const QString &column)
|
||||
{
|
||||
m_columnDefinition.get().after = column;
|
||||
|
||||
return columnReference();
|
||||
}
|
||||
|
||||
template<ColumnReferenceReturn R>
|
||||
typename ColumnDefinitionReference<R>::ColumnReferenceType &
|
||||
ColumnDefinitionReference<R>::autoIncrement()
|
||||
{
|
||||
m_columnDefinition.get().autoIncrement = true;
|
||||
|
||||
return columnReference();
|
||||
}
|
||||
|
||||
template<ColumnReferenceReturn R>
|
||||
typename ColumnDefinitionReference<R>::ColumnReferenceType &
|
||||
ColumnDefinitionReference<R>::charset(const QString &charset)
|
||||
{
|
||||
m_columnDefinition.get().charset = charset;
|
||||
|
||||
return columnReference();
|
||||
}
|
||||
|
||||
template<ColumnReferenceReturn R>
|
||||
typename ColumnDefinitionReference<R>::ColumnReferenceType &
|
||||
ColumnDefinitionReference<R>::collation(const QString &collation)
|
||||
{
|
||||
m_columnDefinition.get().collation = collation;
|
||||
|
||||
return columnReference();
|
||||
}
|
||||
|
||||
template<ColumnReferenceReturn R>
|
||||
typename ColumnDefinitionReference<R>::ColumnReferenceType &
|
||||
ColumnDefinitionReference<R>::comment(const QString &comment)
|
||||
{
|
||||
m_columnDefinition.get().comment = comment;
|
||||
|
||||
return columnReference();
|
||||
}
|
||||
|
||||
template<ColumnReferenceReturn R>
|
||||
typename ColumnDefinitionReference<R>::ColumnReferenceType &
|
||||
ColumnDefinitionReference<R>::defaultValue(const QVariant &value)
|
||||
{
|
||||
m_columnDefinition.get().defaultValue = value;
|
||||
|
||||
return columnReference();
|
||||
}
|
||||
|
||||
template<ColumnReferenceReturn R>
|
||||
typename ColumnDefinitionReference<R>::ColumnReferenceType &
|
||||
ColumnDefinitionReference<R>::first()
|
||||
{
|
||||
m_columnDefinition.get().first = true;
|
||||
|
||||
return columnReference();
|
||||
}
|
||||
|
||||
template<ColumnReferenceReturn R>
|
||||
typename ColumnDefinitionReference<R>::ColumnReferenceType &
|
||||
ColumnDefinitionReference<R>::from(const int startingValue)
|
||||
{
|
||||
m_columnDefinition.get().from = startingValue;
|
||||
|
||||
return columnReference();
|
||||
}
|
||||
|
||||
template<ColumnReferenceReturn R>
|
||||
typename ColumnDefinitionReference<R>::ColumnReferenceType &
|
||||
ColumnDefinitionReference<R>::invisible()
|
||||
{
|
||||
m_columnDefinition.get().invisible = true;
|
||||
|
||||
return columnReference();
|
||||
}
|
||||
|
||||
template<ColumnReferenceReturn R>
|
||||
typename ColumnDefinitionReference<R>::ColumnReferenceType &
|
||||
ColumnDefinitionReference<R>::isUnsigned()
|
||||
{
|
||||
m_columnDefinition.get().isUnsigned = true;
|
||||
|
||||
return columnReference();
|
||||
}
|
||||
|
||||
template<ColumnReferenceReturn R>
|
||||
typename ColumnDefinitionReference<R>::ColumnReferenceType &
|
||||
ColumnDefinitionReference<R>::nullable(const bool value)
|
||||
{
|
||||
m_columnDefinition.get().nullable = value;
|
||||
|
||||
return columnReference();
|
||||
}
|
||||
|
||||
template<ColumnReferenceReturn R>
|
||||
typename ColumnDefinitionReference<R>::ColumnReferenceType &
|
||||
ColumnDefinitionReference<R>::startingValue(const int startingValue)
|
||||
{
|
||||
m_columnDefinition.get().startingValue = startingValue;
|
||||
|
||||
return columnReference();
|
||||
}
|
||||
|
||||
template<ColumnReferenceReturn R>
|
||||
typename ColumnDefinitionReference<R>::ColumnReferenceType &
|
||||
ColumnDefinitionReference<R>::storedAs(const QString &expression)
|
||||
{
|
||||
m_columnDefinition.get().storedAs = expression;
|
||||
|
||||
return columnReference();
|
||||
}
|
||||
|
||||
template<ColumnReferenceReturn R>
|
||||
typename ColumnDefinitionReference<R>::ColumnReferenceType &
|
||||
ColumnDefinitionReference<R>::useCurrent()
|
||||
{
|
||||
m_columnDefinition.get().useCurrent = true;
|
||||
|
||||
return columnReference();
|
||||
}
|
||||
|
||||
template<ColumnReferenceReturn R>
|
||||
typename ColumnDefinitionReference<R>::ColumnReferenceType &
|
||||
ColumnDefinitionReference<R>::useCurrentOnUpdate()
|
||||
{
|
||||
m_columnDefinition.get().useCurrentOnUpdate = true;
|
||||
|
||||
return columnReference();
|
||||
}
|
||||
|
||||
template<ColumnReferenceReturn R>
|
||||
typename ColumnDefinitionReference<R>::ColumnReferenceType &
|
||||
ColumnDefinitionReference<R>::virtualAs(const QString &expression)
|
||||
{
|
||||
m_columnDefinition.get().virtualAs = expression;
|
||||
|
||||
return columnReference();
|
||||
}
|
||||
|
||||
template<ColumnReferenceReturn R>
|
||||
typename ColumnDefinitionReference<R>::ColumnReferenceType &
|
||||
ColumnDefinitionReference<R>::index(const QString &indexName)
|
||||
{
|
||||
if (indexName.isEmpty())
|
||||
m_columnDefinition.get().index_ = true;
|
||||
else
|
||||
m_columnDefinition.get().index_ = indexName;
|
||||
|
||||
return columnReference();
|
||||
}
|
||||
|
||||
template<ColumnReferenceReturn R>
|
||||
typename ColumnDefinitionReference<R>::ColumnReferenceType &
|
||||
ColumnDefinitionReference<R>::primary()
|
||||
{
|
||||
m_columnDefinition.get().primary = true;
|
||||
|
||||
return columnReference();
|
||||
}
|
||||
|
||||
template<ColumnReferenceReturn R>
|
||||
typename ColumnDefinitionReference<R>::ColumnReferenceType &
|
||||
ColumnDefinitionReference<R>::fulltext(const QString &indexName)
|
||||
{
|
||||
if (indexName.isEmpty())
|
||||
m_columnDefinition.get().fulltext = true;
|
||||
else
|
||||
m_columnDefinition.get().fulltext = indexName;
|
||||
|
||||
return columnReference();
|
||||
}
|
||||
|
||||
template<ColumnReferenceReturn R>
|
||||
typename ColumnDefinitionReference<R>::ColumnReferenceType &
|
||||
ColumnDefinitionReference<R>::spatialIndex(const QString &indexName)
|
||||
{
|
||||
if (indexName.isEmpty())
|
||||
m_columnDefinition.get().spatialIndex = true;
|
||||
else
|
||||
m_columnDefinition.get().spatialIndex = indexName;
|
||||
|
||||
return columnReference();
|
||||
}
|
||||
|
||||
template<ColumnReferenceReturn R>
|
||||
typename ColumnDefinitionReference<R>::ColumnReferenceType &
|
||||
ColumnDefinitionReference<R>::unique(const QString &indexName)
|
||||
{
|
||||
if (indexName.isEmpty())
|
||||
m_columnDefinition.get().unique = true;
|
||||
else
|
||||
m_columnDefinition.get().unique = indexName;
|
||||
|
||||
return columnReference();
|
||||
}
|
||||
|
||||
/* private */
|
||||
|
||||
template<ColumnReferenceReturn R>
|
||||
typename ColumnDefinitionReference<R>::ColumnReferenceType &
|
||||
ColumnDefinitionReference<R>::columnReference()
|
||||
{
|
||||
return static_cast<ColumnDefinitionReference<R>::ColumnReferenceType &>(*this);
|
||||
}
|
||||
|
||||
} // namespace Orm::SchemaNs
|
||||
|
||||
TINYORM_END_COMMON_NAMESPACE
|
||||
|
||||
#endif // ORM_SCHEMA_COLUMNDEFINITIONREFERENCE_HPP
|
||||
63
include/orm/schema/foreignidcolumndefinitionreference.hpp
Normal file
63
include/orm/schema/foreignidcolumndefinitionreference.hpp
Normal file
@@ -0,0 +1,63 @@
|
||||
#pragma once
|
||||
#ifndef ORM_SCHEMA_FOREIGNIDCOLUMNDEFINITIONREFERENCE_HPP
|
||||
#define ORM_SCHEMA_FOREIGNIDCOLUMNDEFINITIONREFERENCE_HPP
|
||||
|
||||
#include "orm/macros/systemheader.hpp"
|
||||
TINY_SYSTEM_HEADER
|
||||
|
||||
#include "orm/constants.hpp"
|
||||
#include "orm/schema/foreignkeydefinitionreference.hpp"
|
||||
|
||||
TINYORM_BEGIN_COMMON_NAMESPACE
|
||||
|
||||
namespace Orm::SchemaNs
|
||||
{
|
||||
|
||||
class Blueprint;
|
||||
|
||||
/*! Reference class to the ColumnDefinition provides setters with a nice API using
|
||||
terser syntax for the foreign key column. */
|
||||
class SHAREDLIB_EXPORT ForeignIdColumnDefinitionReference :
|
||||
public ColumnDefinitionReference<ForeignIdColumnDefinitionReference>
|
||||
{
|
||||
// To access m_columnDefinition data member
|
||||
friend ForeignKeyDefinitionReference;
|
||||
|
||||
public:
|
||||
/*! Constructor. */
|
||||
ForeignIdColumnDefinitionReference( // NOLINT(google-explicit-constructor)
|
||||
Blueprint &blueprint,
|
||||
ColumnDefinitionReference<> columnDefinitionReference);
|
||||
/*! Default destructor. */
|
||||
inline ~ForeignIdColumnDefinitionReference() = default;
|
||||
|
||||
/*! Create a foreign key constraint on this column referencing the "id" column
|
||||
of the conventionally related table. */
|
||||
ForeignKeyDefinitionReference
|
||||
constrained(const QString &table = "", const QString &column = Constants::ID);
|
||||
|
||||
/*! Specify the referenced columns. */
|
||||
ForeignKeyDefinitionReference references(const QVector<QString> &columns);
|
||||
/*! Specify the referenced column. */
|
||||
template<typename = void>
|
||||
ForeignKeyDefinitionReference references(const QString &column);
|
||||
|
||||
private:
|
||||
/*! Reference to the schema builder blueprint instance. */
|
||||
Blueprint &m_blueprint;
|
||||
/*! Reference to a column definition. */
|
||||
std::reference_wrapper<ColumnDefinition> m_columnDefinition;
|
||||
};
|
||||
|
||||
template<typename>
|
||||
ForeignKeyDefinitionReference
|
||||
ForeignIdColumnDefinitionReference::references(const QString &column)
|
||||
{
|
||||
return references(QVector<QString> {column});
|
||||
}
|
||||
|
||||
} // namespace Orm::SchemaNs
|
||||
|
||||
TINYORM_END_COMMON_NAMESPACE
|
||||
|
||||
#endif // ORM_SCHEMA_FOREIGNIDCOLUMNDEFINITIONREFERENCE_HPP
|
||||
71
include/orm/schema/foreignkeydefinitionreference.hpp
Normal file
71
include/orm/schema/foreignkeydefinitionreference.hpp
Normal file
@@ -0,0 +1,71 @@
|
||||
#pragma once
|
||||
#ifndef ORM_SCHEMA_FOREIGNKEYDEFINITIONREFERENCE_HPP
|
||||
#define ORM_SCHEMA_FOREIGNKEYDEFINITIONREFERENCE_HPP
|
||||
|
||||
#include "orm/macros/systemheader.hpp"
|
||||
TINY_SYSTEM_HEADER
|
||||
|
||||
#include "orm/macros/export.hpp"
|
||||
#include "orm/schema/columndefinitionreference.hpp"
|
||||
|
||||
TINYORM_BEGIN_COMMON_NAMESPACE
|
||||
|
||||
namespace Orm::SchemaNs
|
||||
{
|
||||
|
||||
/*! Reference class to the ColumnDefinition, provides setters with a nice API
|
||||
for the foreign key column. */
|
||||
class SHAREDLIB_EXPORT ForeignKeyDefinitionReference
|
||||
{
|
||||
public:
|
||||
/*! Constructor. */
|
||||
ForeignKeyDefinitionReference( // NOLINT(google-explicit-constructor)
|
||||
ColumnDefinitionReference<> columnDefinitionReference);
|
||||
/*! Constructor. */
|
||||
ForeignKeyDefinitionReference( // NOLINT(google-explicit-constructor)
|
||||
ForeignIdColumnDefinitionReference foreignIdColumnReference);
|
||||
/*! Default destructor. */
|
||||
inline ~ForeignKeyDefinitionReference() = default;
|
||||
|
||||
/*! Specify the referenced columns. */
|
||||
ForeignKeyDefinitionReference &references(const QVector<QString> &columns);
|
||||
/*! Specify the referenced column. */
|
||||
template<typename = void>
|
||||
ForeignKeyDefinitionReference &references(const QString &column);
|
||||
|
||||
/*! Specify the referenced table. */
|
||||
ForeignKeyDefinitionReference &on(const QString &table);
|
||||
|
||||
/*! Add an ON DELETE action. */
|
||||
ForeignKeyDefinitionReference &onDelete(const QString &action);
|
||||
/*! Add an ON UPDATE action. */
|
||||
ForeignKeyDefinitionReference &onUpdate(const QString &action);
|
||||
|
||||
/*! Indicate that updates should cascade. */
|
||||
ForeignKeyDefinitionReference &cascadeOnUpdate();
|
||||
/*! Indicate that updates should be restricted. */
|
||||
ForeignKeyDefinitionReference &restrictOnUpdate();
|
||||
/*! Indicate that deletes should cascade. */
|
||||
ForeignKeyDefinitionReference &cascadeOnDelete();
|
||||
/*! Indicate that deletes should be restricted. */
|
||||
ForeignKeyDefinitionReference &restrictOnDelete();
|
||||
/*! Indicate that deletes should set the foreign key value to null. */
|
||||
ForeignKeyDefinitionReference &nullOnDelete();
|
||||
|
||||
private:
|
||||
/*! Reference to a column definition. */
|
||||
std::reference_wrapper<ColumnDefinition> m_columnDefinition;
|
||||
};
|
||||
|
||||
template<typename>
|
||||
ForeignKeyDefinitionReference &
|
||||
ForeignKeyDefinitionReference::references(const QString &column)
|
||||
{
|
||||
return references(QVector<QString> {column});
|
||||
}
|
||||
|
||||
} // namespace Orm::SchemaNs
|
||||
|
||||
TINYORM_END_COMMON_NAMESPACE
|
||||
|
||||
#endif // ORM_SCHEMA_FOREIGNKEYDEFINITIONREFERENCE_HPP
|
||||
@@ -9,7 +9,7 @@ TINY_SYSTEM_HEADER
|
||||
|
||||
TINYORM_BEGIN_COMMON_NAMESPACE
|
||||
|
||||
namespace Orm::Schema::Grammars
|
||||
namespace Orm::SchemaNs::Grammars
|
||||
{
|
||||
|
||||
/*! MySql schema grammar. */
|
||||
@@ -23,11 +23,275 @@ namespace Orm::Schema::Grammars
|
||||
/*! Virtual destructor. */
|
||||
inline ~MySqlSchemaGrammar() override = default;
|
||||
|
||||
/* Compile methods for the SchemaBuilder */
|
||||
/*! Compile a create database command. */
|
||||
QString compileCreateDatabase(const QString &name,
|
||||
DatabaseConnection &connection) const override;
|
||||
/*! Compile a drop database if exists command. */
|
||||
QString compileDropDatabaseIfExists(const QString &name) const override;
|
||||
|
||||
/*! Compile the SQL needed to drop all tables. */
|
||||
QString compileDropAllTables(const QVector<QString> &tables) const override;
|
||||
/*! Compile the SQL needed to drop all views. */
|
||||
QString compileDropAllViews(const QVector<QString> &views) const override;
|
||||
|
||||
/*! Compile the SQL needed to retrieve all table names. */
|
||||
QString compileGetAllTables() const override;
|
||||
/*! Compile the SQL needed to retrieve all view names. */
|
||||
QString compileGetAllViews() const override;
|
||||
|
||||
/*! Compile the command to enable foreign key constraints. */
|
||||
QString compileEnableForeignKeyConstraints() const override;
|
||||
/*! Compile the command to disable foreign key constraints. */
|
||||
QString compileDisableForeignKeyConstraints() const override;
|
||||
|
||||
/*! Compile the query to determine the list of tables. */
|
||||
QString compileTableExists() const override;
|
||||
/*! Compile the query to determine the list of columns. */
|
||||
QString compileColumnListing(const QString &table = "") const override;
|
||||
|
||||
/* Compile methods for commands */
|
||||
/*! Compile a create table command. */
|
||||
QVector<QString>
|
||||
compileCreate(const Blueprint &blueprint, const ColumnDefinition &command,
|
||||
const DatabaseConnection &connection) const;
|
||||
|
||||
/*! Compile a drop table command. */
|
||||
QVector<QString> compileDrop(const Blueprint &blueprint,
|
||||
const ColumnDefinition &command) const;
|
||||
/*! Compile a drop table (if exists) command. */
|
||||
QVector<QString> compileDropIfExists(const Blueprint &blueprint,
|
||||
const ColumnDefinition &command) const;
|
||||
|
||||
/*! Compile a rename table command. */
|
||||
QVector<QString> compileRename(const Blueprint &blueprint,
|
||||
const ColumnDefinition &command) const;
|
||||
|
||||
/*! Compile an add column command. */
|
||||
QVector<QString> compileAdd(const Blueprint &blueprint,
|
||||
const ColumnDefinition &command) const;
|
||||
/*! Compile a drop column command. */
|
||||
QVector<QString> compileDropColumn(const Blueprint &blueprint,
|
||||
const ColumnDefinition &command) const;
|
||||
/*! Compile a rename column command. */
|
||||
QVector<QString> compileRenameColumn(const Blueprint &blueprint,
|
||||
const ColumnDefinition &command) const;
|
||||
|
||||
/*! Compile a primary key command. */
|
||||
QVector<QString> compilePrimary(const Blueprint &blueprint,
|
||||
const ColumnDefinition &command) const;
|
||||
/*! Compile a unique key command. */
|
||||
QVector<QString> compileUnique(const Blueprint &blueprint,
|
||||
const ColumnDefinition &command) const;
|
||||
/*! Compile a plain index key command. */
|
||||
QVector<QString> compileIndex(const Blueprint &blueprint,
|
||||
const ColumnDefinition &command) const;
|
||||
/*! Compile a fulltext index key command. */
|
||||
QVector<QString> compileFullText(const Blueprint &blueprint,
|
||||
const ColumnDefinition &command) const override;
|
||||
/*! Compile a spatial index key command. */
|
||||
QVector<QString> compileSpatialIndex(const Blueprint &blueprint,
|
||||
const ColumnDefinition &command) const;
|
||||
|
||||
/*! Compile a drop primary key command. */
|
||||
QVector<QString> compileDropPrimary(const Blueprint &blueprint,
|
||||
const ColumnDefinition &command) const;
|
||||
/*! Compile a drop unique key command. */
|
||||
inline QVector<QString> compileDropUnique(const Blueprint &blueprint,
|
||||
const ColumnDefinition &command) const;
|
||||
/*! Compile a drop index command. */
|
||||
QVector<QString> compileDropIndex(const Blueprint &blueprint,
|
||||
const ColumnDefinition &command) const;
|
||||
/*! Compile a drop fulltext index command. */
|
||||
inline QVector<QString>
|
||||
compileDropFullText(const Blueprint &blueprint,
|
||||
const ColumnDefinition &command) const override;
|
||||
/*! Compile a drop spatial index command. */
|
||||
inline QVector<QString>
|
||||
compileDropSpatialIndex(const Blueprint &blueprint,
|
||||
const ColumnDefinition &command) const;
|
||||
|
||||
/*! Compile a drop foreign key command. */
|
||||
QVector<QString> compileDropForeign(const Blueprint &blueprint,
|
||||
const ColumnDefinition &command) const;
|
||||
|
||||
/*! Compile a rename index command. */
|
||||
QVector<QString> compileRenameIndex(const Blueprint &blueprint,
|
||||
const ColumnDefinition &command) const;
|
||||
|
||||
/*! Map a command name to SchemaGrammar::compileXx() methods. */
|
||||
QVector<QString>
|
||||
invokeCompileMethod(const ColumnDefinition &command,
|
||||
const DatabaseConnection &connection,
|
||||
const Blueprint &blueprint) const override;
|
||||
|
||||
protected:
|
||||
// BUG schema, change after upgrade to QtCreator with clang 13 silverqx
|
||||
/*! Expose column types. */
|
||||
// using enum ColumnType;
|
||||
|
||||
/*! Create the main create table clause. */
|
||||
QString
|
||||
compileCreateTable(const Blueprint &blueprint, const ColumnDefinition &command,
|
||||
const DatabaseConnection &connection) const;
|
||||
/*! Add the column modifiers to the definition. */
|
||||
QString addModifiers(QString &&sql,
|
||||
const ColumnDefinition &column) const override;
|
||||
|
||||
/*! Append the character set specifications to a command. */
|
||||
void compileCreateEncoding(QString &sql, const DatabaseConnection &connection,
|
||||
const Blueprint &blueprint) const;
|
||||
/*! Append the engine specifications to a command. */
|
||||
void compileCreateEngine(QString &sql, const DatabaseConnection &connection,
|
||||
const Blueprint &blueprint) const;
|
||||
/*! Compile the auto-incrementing column starting values. */
|
||||
QVector<QString>
|
||||
compileAutoIncrementStartingValues(const Blueprint &blueprint) const;
|
||||
|
||||
/*! Compile an index creation command. */
|
||||
QString compileKey(const Blueprint &blueprint, const ColumnDefinition &command,
|
||||
const QString &type) const;
|
||||
|
||||
/*! Wrap a single string in keyword identifiers. */
|
||||
QString wrapValue(QString value) const override;
|
||||
|
||||
/*! Escape all MySQL spacial characters desribed in String Literal docs. */
|
||||
QString addSlashes(QString value) const;
|
||||
|
||||
/*! Get the SQL for the column data type. */
|
||||
QString getType(const ColumnDefinition &column) const override;
|
||||
|
||||
/*! Create the column definition for a char type. */
|
||||
QString typeChar(const ColumnDefinition &column) const;
|
||||
/*! Create the column definition for a string type. */
|
||||
QString typeString(const ColumnDefinition &column) const;
|
||||
/*! Create the column definition for a tiny text type. */
|
||||
QString typeTinyText(const ColumnDefinition &column) const;
|
||||
/*! Create the column definition for a text type. */
|
||||
QString typeText(const ColumnDefinition &column) const;
|
||||
/*! Create the column definition for a medium text type. */
|
||||
QString typeMediumText(const ColumnDefinition &column) const;
|
||||
/*! Create the column definition for a long text type. */
|
||||
QString typeLongText(const ColumnDefinition &column) const;
|
||||
/*! Create the column definition for a big integer type. */
|
||||
QString typeBigInteger(const ColumnDefinition &column) const;
|
||||
/*! Create the column definition for an integer type. */
|
||||
QString typeInteger(const ColumnDefinition &column) const;
|
||||
/*! Create the column definition for a medium integer type. */
|
||||
QString typeMediumInteger(const ColumnDefinition &column) const;
|
||||
/*! Create the column definition for a tiny integer type. */
|
||||
QString typeTinyInteger(const ColumnDefinition &column) const;
|
||||
/*! Create the column definition for a small integer type. */
|
||||
QString typeSmallInteger(const ColumnDefinition &column) const;
|
||||
/*! Create the column definition for a float type. */
|
||||
QString typeFloat(const ColumnDefinition &column) const;
|
||||
/*! Create the column definition for a double type. */
|
||||
QString typeDouble(const ColumnDefinition &column) const;
|
||||
/*! Create the column definition for a decimal type. */
|
||||
QString typeDecimal(const ColumnDefinition &column) const;
|
||||
/*! Create the column definition for a boolean type. */
|
||||
QString typeBoolean(const ColumnDefinition &column) const;
|
||||
/*! Create the column definition for an enumeration type. */
|
||||
QString typeEnum(const ColumnDefinition &column) const;
|
||||
/*! Create the column definition for a set enumeration type. */
|
||||
QString typeSet(const ColumnDefinition &column) const;
|
||||
/*! Create the column definition for a json type. */
|
||||
QString typeJson(const ColumnDefinition &column) const;
|
||||
/*! Create the column definition for a jsonb type. */
|
||||
QString typeJsonb(const ColumnDefinition &column) const;
|
||||
/*! Create the column definition for a date type. */
|
||||
QString typeDate(const ColumnDefinition &column) const;
|
||||
/*! Create the column definition for a date-time type. */
|
||||
QString typeDateTime(const ColumnDefinition &column) const;
|
||||
/*! Create the column definition for a date-time (with time zone) type. */
|
||||
QString typeDateTimeTz(const ColumnDefinition &column) const;
|
||||
/*! Create the column definition for a time type. */
|
||||
QString typeTime(const ColumnDefinition &column) const;
|
||||
/*! Create the column definition for a time (with time zone) type. */
|
||||
QString typeTimeTz(const ColumnDefinition &column) const;
|
||||
/*! Create the column definition for a timestamp type. */
|
||||
QString typeTimestamp(const ColumnDefinition &column) const;
|
||||
/*! Create the column definition for a timestamp (with time zone) type. */
|
||||
QString typeTimestampTz(const ColumnDefinition &column) const;
|
||||
/*! Create the column definition for a year type. */
|
||||
QString typeYear(const ColumnDefinition &column) const;
|
||||
/*! Create the column definition for a binary type. */
|
||||
QString typeBinary(const ColumnDefinition &column) const;
|
||||
/*! Create the column definition for a uuid type. */
|
||||
QString typeUuid(const ColumnDefinition &column) const;
|
||||
/*! Create the column definition for an IP address type. */
|
||||
QString typeIpAddress(const ColumnDefinition &column) const;
|
||||
/*! Create the column definition for a MAC address type. */
|
||||
QString typeMacAddress(const ColumnDefinition &column) const;
|
||||
/*! Create the column definition for a spatial Geometry type. */
|
||||
QString typeGeometry(const ColumnDefinition &column) const;
|
||||
/*! Create the column definition for a spatial Point type. */
|
||||
QString typePoint(const ColumnDefinition &column) const;
|
||||
/*! Create the column definition for a spatial LineString type. */
|
||||
QString typeLineString(const ColumnDefinition &column) const;
|
||||
/*! Create the column definition for a spatial Polygon type. */
|
||||
QString typePolygon(const ColumnDefinition &column) const;
|
||||
/*! Create the column definition for a spatial GeometryCollection type. */
|
||||
QString typeGeometryCollection(const ColumnDefinition &column) const;
|
||||
/*! Create the column definition for a spatial MultiPoint type. */
|
||||
QString typeMultiPoint(const ColumnDefinition &column) const;
|
||||
/*! Create the column definition for a spatial MultiLineString type. */
|
||||
QString typeMultiLineString(const ColumnDefinition &column) const;
|
||||
/*! Create the column definition for a spatial MultiPolygon type. */
|
||||
QString typeMultiPolygon(const ColumnDefinition &column) const;
|
||||
/*! Create the column definition for a generated, computed column type. */
|
||||
QString typeComputed(const ColumnDefinition &column) const override;
|
||||
|
||||
/*! Get the SQL for a generated virtual column modifier. */
|
||||
QString modifyVirtualAs(const ColumnDefinition &column) const;
|
||||
/*! Get the SQL for a generated stored column modifier. */
|
||||
QString modifyStoredAs(const ColumnDefinition &column) const;
|
||||
/*! Get the SQL for an unsigned column modifier. */
|
||||
QString modifyUnsigned(const ColumnDefinition &column) const;
|
||||
/*! Get the SQL for a character set column modifier.*/
|
||||
QString modifyCharset(const ColumnDefinition &column) const;
|
||||
/*! Get the SQL for a collation column modifier. */
|
||||
QString modifyCollate(const ColumnDefinition &column) const;
|
||||
/*! Get the SQL for a nullable column modifier. */
|
||||
QString modifyNullable(const ColumnDefinition &column) const;
|
||||
/*! Get the SQL for an invisible column modifier. */
|
||||
QString modifyInvisible(const ColumnDefinition &column) const;
|
||||
/*! Get the SQL for a default column modifier. */
|
||||
QString modifyDefault(const ColumnDefinition &column) const;
|
||||
/*! Get the SQL for an auto-increment column modifier. */
|
||||
QString modifyIncrement(const ColumnDefinition &column) const;
|
||||
/*! Get the SQL for a "first" column modifier. */
|
||||
QString modifyFirst(const ColumnDefinition &column) const;
|
||||
/*! Get the SQL for an "after" column modifier. */
|
||||
QString modifyAfter(const ColumnDefinition &column) const;
|
||||
/*! Get the SQL for a "comment" column modifier. */
|
||||
QString modifyComment(const ColumnDefinition &column) const;
|
||||
/*! Get the SQL for a SRID column modifier. */
|
||||
QString modifySrid(const ColumnDefinition &column) const;
|
||||
};
|
||||
|
||||
} // namespace Orm::Schema::Grammars
|
||||
QVector<QString>
|
||||
MySqlSchemaGrammar::compileDropUnique(const Blueprint &blueprint,
|
||||
const ColumnDefinition &command) const
|
||||
{
|
||||
return compileDropIndex(blueprint, command);
|
||||
}
|
||||
|
||||
QVector<QString>
|
||||
MySqlSchemaGrammar::compileDropFullText(const Blueprint &blueprint,
|
||||
const ColumnDefinition &command) const
|
||||
{
|
||||
return compileDropIndex(blueprint, command);
|
||||
}
|
||||
|
||||
QVector<QString>
|
||||
MySqlSchemaGrammar::compileDropSpatialIndex(const Blueprint &blueprint,
|
||||
const ColumnDefinition &command) const
|
||||
{
|
||||
return compileDropIndex(blueprint, command);
|
||||
}
|
||||
|
||||
} // namespace Orm::SchemaNs::Grammars
|
||||
|
||||
TINYORM_END_COMMON_NAMESPACE
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ TINY_SYSTEM_HEADER
|
||||
|
||||
TINYORM_BEGIN_COMMON_NAMESPACE
|
||||
|
||||
namespace Orm::Schema::Grammars
|
||||
namespace Orm::SchemaNs::Grammars
|
||||
{
|
||||
|
||||
/*! PostgreSql schemma grammar. */
|
||||
@@ -23,11 +23,36 @@ namespace Orm::Schema::Grammars
|
||||
/*! Virtual destructor. */
|
||||
inline ~PostgresSchemaGrammar() override = default;
|
||||
|
||||
/* Compile methods for the SchemaBuilder */
|
||||
/*! Compile the command to enable foreign key constraints. */
|
||||
QString compileEnableForeignKeyConstraints() const override;
|
||||
/*! Compile the command to disable foreign key constraints. */
|
||||
QString compileDisableForeignKeyConstraints() const override;
|
||||
|
||||
/*! Compile the query to determine the list of columns. */
|
||||
QString compileColumnListing(const QString &table = "") const override;
|
||||
|
||||
/* Compile methods for commands */
|
||||
/*! Compile a foreign key command. */
|
||||
QVector<QString> compileForeign(const Blueprint &blueprint,
|
||||
const ColumnDefinition &command) const override;
|
||||
|
||||
/*! Run command's compile method and return SQL queries. */
|
||||
QVector<QString>
|
||||
invokeCompileMethod(const ColumnDefinition &command,
|
||||
const DatabaseConnection &connection,
|
||||
const Blueprint &blueprint) const override;
|
||||
|
||||
protected:
|
||||
/*! Add the column modifiers to the definition. */
|
||||
QString addModifiers(QString &&sql,
|
||||
const ColumnDefinition &column) const override;
|
||||
|
||||
/*! Get the SQL for the column data type. */
|
||||
QString getType(const ColumnDefinition &column) const override;
|
||||
};
|
||||
|
||||
} // namespace Orm::Schema::Grammars
|
||||
} // namespace Orm::SchemaNs::Grammars
|
||||
|
||||
TINYORM_END_COMMON_NAMESPACE
|
||||
|
||||
|
||||
@@ -5,11 +5,19 @@
|
||||
#include "orm/macros/systemheader.hpp"
|
||||
TINY_SYSTEM_HEADER
|
||||
|
||||
#include <range/v3/range/conversion.hpp>
|
||||
#include <range/v3/view/transform.hpp>
|
||||
|
||||
#include "orm/basegrammar.hpp"
|
||||
|
||||
TINYORM_BEGIN_COMMON_NAMESPACE
|
||||
|
||||
namespace Orm::Schema::Grammars
|
||||
namespace Orm::SchemaNs
|
||||
{
|
||||
class Blueprint;
|
||||
class ColumnDefinition;
|
||||
|
||||
namespace Grammars
|
||||
{
|
||||
|
||||
/*! Database schema grammar base class. */
|
||||
@@ -23,13 +31,96 @@ namespace Orm::Schema::Grammars
|
||||
/*! Pure virtual destructor. */
|
||||
inline ~SchemaGrammar() override = 0;
|
||||
|
||||
/* Compile methods for the SchemaBuilder */
|
||||
/*! Compile a create database command. */
|
||||
virtual QString compileCreateDatabase(const QString &name,
|
||||
DatabaseConnection &connection) const;
|
||||
/*! Compile a drop database if exists command. */
|
||||
virtual QString compileDropDatabaseIfExists(const QString &name) const;
|
||||
|
||||
/*! Compile the SQL needed to drop all tables. */
|
||||
virtual QString compileDropAllTables(const QVector<QString> &tables) const;
|
||||
/*! Compile the SQL needed to drop all views. */
|
||||
virtual QString compileDropAllViews(const QVector<QString> &views) const;
|
||||
|
||||
/*! Compile the SQL needed to retrieve all table names. */
|
||||
virtual QString compileGetAllTables() const;
|
||||
/*! Compile the SQL needed to retrieve all view names. */
|
||||
virtual QString compileGetAllViews() const;
|
||||
|
||||
/*! Compile the command to enable foreign key constraints. */
|
||||
virtual QString compileEnableForeignKeyConstraints() const = 0;
|
||||
/*! Compile the command to disable foreign key constraints. */
|
||||
virtual QString compileDisableForeignKeyConstraints() const = 0;
|
||||
|
||||
/*! Compile the query to determine the list of tables. */
|
||||
virtual QString compileTableExists() const;
|
||||
/*! Compile the query to determine the list of columns. */
|
||||
virtual QString compileColumnListing(const QString &table = "") const = 0;
|
||||
|
||||
/* Compile methods for commands */
|
||||
/*! Compile a fulltext index key command. */
|
||||
virtual QVector<QString>
|
||||
compileFullText(const Blueprint &blueprint,
|
||||
const ColumnDefinition &command) const;
|
||||
|
||||
/*! Compile a foreign key command. */
|
||||
virtual QVector<QString>
|
||||
compileForeign(const Blueprint &blueprint,
|
||||
const ColumnDefinition &command) const;
|
||||
|
||||
/*! Compile a drop fulltext index command. */
|
||||
virtual QVector<QString>
|
||||
compileDropFullText(const Blueprint &blueprint,
|
||||
const ColumnDefinition &command) const;
|
||||
|
||||
/*! Wrap a value in keyword identifiers. */
|
||||
QString wrap(const ColumnDefinition &column, bool prefixAlias = false) const;
|
||||
/*! Wrap a table in keyword identifiers. */
|
||||
QString wrapTable(const Blueprint &blueprint) const;
|
||||
/*! Add a prefix to an array of values. */
|
||||
template<ColumnContainer T>
|
||||
QVector<QString> prefixArray(const QString &prefix, const T &values) const;
|
||||
|
||||
/*! Run command's compile method and return SQL queries. */
|
||||
virtual QVector<QString>
|
||||
invokeCompileMethod(const ColumnDefinition &command,
|
||||
const DatabaseConnection &connection,
|
||||
const Blueprint &blueprint) const = 0;
|
||||
|
||||
protected:
|
||||
/*! Get the SQL for the column data type. */
|
||||
virtual QString getType(const ColumnDefinition &column) const = 0;
|
||||
/*! Compile the blueprint's column definitions. */
|
||||
QStringList getColumns(const Blueprint &blueprint) const;
|
||||
|
||||
/*! Format a value so that it can be used in "default" clauses. */
|
||||
QString getDefaultValue(const QVariant &value) const;
|
||||
|
||||
/*! Add the column modifiers to the definition. */
|
||||
virtual QString
|
||||
addModifiers(QString &&sql, const ColumnDefinition &column) const = 0;
|
||||
|
||||
/*! Create the column definition for a generated, computed column type. */
|
||||
virtual QString typeComputed(const ColumnDefinition &column) const;
|
||||
};
|
||||
|
||||
SchemaGrammar::~SchemaGrammar() = default;
|
||||
|
||||
} // namespace Orm::Schema::Grammars
|
||||
template<ColumnContainer T>
|
||||
QVector<QString>
|
||||
SchemaGrammar::prefixArray(const QString &prefix, const T &values) const
|
||||
{
|
||||
return values
|
||||
| ranges::views::transform([&prefix](const auto &value)
|
||||
{
|
||||
return SPACE_IN.arg(prefix, value);
|
||||
})
|
||||
| ranges::to<QVector<QString>>();
|
||||
}
|
||||
|
||||
} // namespace Grammars
|
||||
} // namespace Orm::SchemaNs
|
||||
|
||||
TINYORM_END_COMMON_NAMESPACE
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ TINY_SYSTEM_HEADER
|
||||
|
||||
TINYORM_BEGIN_COMMON_NAMESPACE
|
||||
|
||||
namespace Orm::Schema::Grammars
|
||||
namespace Orm::SchemaNs::Grammars
|
||||
{
|
||||
|
||||
/*! SQLite schemma grammar. */
|
||||
@@ -23,11 +23,36 @@ namespace Orm::Schema::Grammars
|
||||
/*! Virtual destructor. */
|
||||
inline ~SQLiteSchemaGrammar() override = default;
|
||||
|
||||
/* Compile methods for the SchemaBuilder */
|
||||
/*! Compile the command to enable foreign key constraints. */
|
||||
QString compileEnableForeignKeyConstraints() const override;
|
||||
/*! Compile the command to disable foreign key constraints. */
|
||||
QString compileDisableForeignKeyConstraints() const override;
|
||||
|
||||
/*! Compile the query to determine the list of columns. */
|
||||
QString compileColumnListing(const QString &table = "") const override;
|
||||
|
||||
/* Compile methods for commands */
|
||||
/*! Compile a foreign key command. */
|
||||
QVector<QString> compileForeign(const Blueprint &blueprint,
|
||||
const ColumnDefinition &command) const override;
|
||||
|
||||
/*! Run command's compile method and return SQL queries. */
|
||||
QVector<QString>
|
||||
invokeCompileMethod(const ColumnDefinition &command,
|
||||
const DatabaseConnection &connection,
|
||||
const Blueprint &blueprint) const override;
|
||||
|
||||
protected:
|
||||
/*! Add the column modifiers to the definition. */
|
||||
QString addModifiers(QString &&sql,
|
||||
const ColumnDefinition &column) const override;
|
||||
|
||||
/*! Get the SQL for the column data type. */
|
||||
QString getType(const ColumnDefinition &column) const override;
|
||||
};
|
||||
|
||||
} // namespace Orm::Schema::Grammars
|
||||
} // namespace Orm::SchemaNs::Grammars
|
||||
|
||||
TINYORM_END_COMMON_NAMESPACE
|
||||
|
||||
|
||||
@@ -9,10 +9,10 @@ TINY_SYSTEM_HEADER
|
||||
|
||||
TINYORM_BEGIN_COMMON_NAMESPACE
|
||||
|
||||
namespace Orm::Schema
|
||||
namespace Orm::SchemaNs
|
||||
{
|
||||
|
||||
/*! MySql schema repository class. */
|
||||
/*! MySql schema builder class. */
|
||||
class SHAREDLIB_EXPORT MySqlSchemaBuilder : public SchemaBuilder
|
||||
{
|
||||
Q_DISABLE_COPY(MySqlSchemaBuilder)
|
||||
@@ -24,11 +24,29 @@ namespace Orm::Schema
|
||||
/*! Virtual destructor. */
|
||||
inline ~MySqlSchemaBuilder() override = default;
|
||||
|
||||
/*! Create a database in the schema. */
|
||||
QSqlQuery createDatabase(const QString &name) const override;
|
||||
/*! Drop a database from the schema if the database exists. */
|
||||
QSqlQuery dropDatabaseIfExists(const QString &name) const override;
|
||||
|
||||
/*! Drop all tables from the database. */
|
||||
void dropAllTables() const override;
|
||||
/*! Drop all views from the database. */
|
||||
void dropAllViews() const override;
|
||||
|
||||
/*! Get all of the table names for the database. */
|
||||
QSqlQuery getAllTables() const override;
|
||||
/*! Get all of the view names for the database. */
|
||||
QSqlQuery getAllViews() const override;
|
||||
|
||||
/*! Get the column listing for a given table. */
|
||||
QStringList getColumnListing(const QString &table) const override;
|
||||
|
||||
/*! Determine if the given table exists. */
|
||||
bool hasTable(const QString &table) const override;
|
||||
};
|
||||
|
||||
} // namespace Orm::Schema
|
||||
} // namespace Orm::SchemaNs
|
||||
|
||||
TINYORM_END_COMMON_NAMESPACE
|
||||
|
||||
|
||||
@@ -9,10 +9,10 @@ TINY_SYSTEM_HEADER
|
||||
|
||||
TINYORM_BEGIN_COMMON_NAMESPACE
|
||||
|
||||
namespace Orm::Schema
|
||||
namespace Orm::SchemaNs
|
||||
{
|
||||
|
||||
/*! PostgreSql schema repository class. */
|
||||
/*! PostgreSql schema builder class. */
|
||||
class SHAREDLIB_EXPORT PostgresSchemaBuilder : public SchemaBuilder
|
||||
{
|
||||
Q_DISABLE_COPY(PostgresSchemaBuilder)
|
||||
@@ -33,7 +33,7 @@ namespace Orm::Schema
|
||||
parseSchemaAndTable(const QString &table) const;
|
||||
};
|
||||
|
||||
} // namespace Orm::Schema
|
||||
} // namespace Orm::SchemaNs
|
||||
|
||||
TINYORM_END_COMMON_NAMESPACE
|
||||
|
||||
|
||||
@@ -5,11 +5,13 @@
|
||||
#include "orm/macros/systemheader.hpp"
|
||||
TINY_SYSTEM_HEADER
|
||||
|
||||
#include <QStringList>
|
||||
#include <QtGlobal>
|
||||
#include <QtSql/QSqlQuery>
|
||||
|
||||
#include "orm/macros/commonnamespace.hpp"
|
||||
#include "orm/macros/export.hpp"
|
||||
// CUR check this on clean project silverqx
|
||||
// Include the blueprint here so a user doesn't have to
|
||||
#include "orm/schema/blueprint.hpp"
|
||||
|
||||
TINYORM_BEGIN_COMMON_NAMESPACE
|
||||
|
||||
@@ -17,14 +19,14 @@ namespace Orm
|
||||
{
|
||||
class DatabaseConnection;
|
||||
|
||||
namespace Schema
|
||||
namespace SchemaNs
|
||||
{
|
||||
namespace Grammars
|
||||
{
|
||||
class SchemaGrammar;
|
||||
}
|
||||
|
||||
/*! Database schema repository base class. */
|
||||
/*! Database schema builder base class. */
|
||||
class SHAREDLIB_EXPORT SchemaBuilder
|
||||
{
|
||||
Q_DISABLE_COPY(SchemaBuilder)
|
||||
@@ -35,19 +37,103 @@ namespace Grammars
|
||||
/*! Virtual destructor. */
|
||||
inline virtual ~SchemaBuilder() = default;
|
||||
|
||||
/*! Create a database in the schema. */
|
||||
virtual QSqlQuery createDatabase(const QString &name) const;
|
||||
/*! Drop a database from the schema if the database exists. */
|
||||
virtual QSqlQuery dropDatabaseIfExists(const QString &name) const;
|
||||
|
||||
/*! Create a new table on the schema. */
|
||||
void create(const QString &table,
|
||||
const std::function<void(Blueprint &)> &callback) const;
|
||||
/*! Modify a table on the schema. */
|
||||
void table(const QString &table,
|
||||
const std::function<void(Blueprint &)> &callback) const;
|
||||
|
||||
/*! Drop a table from the schema. */
|
||||
void drop(const QString &table) const;
|
||||
/*! Drop a table from the schema if it exists. */
|
||||
void dropIfExists(const QString &table) const;
|
||||
|
||||
/*! Rename a table on the schema. */
|
||||
void rename(const QString &from, const QString &to) const;
|
||||
|
||||
/*! Drop columns from a table schema. */
|
||||
void dropColumns(const QString &table, const QVector<QString> &columns) const;
|
||||
/*! Drop columns from a table schema. */
|
||||
template<QStringConcept ...Args>
|
||||
void dropColumns(const QString &table, Args &&...columns);
|
||||
/*! Drop one column from a table schema. */
|
||||
void dropColumn(const QString &table, const QString &column) const;
|
||||
|
||||
/*! Rename the given column on the schema. */
|
||||
void renameColumn(const QString &table, const QString &from, const QString &to);
|
||||
|
||||
/*! Drop all tables from the database. */
|
||||
virtual void dropAllTables() const;
|
||||
/*! Drop all views from the database. */
|
||||
virtual void dropAllViews() const;
|
||||
/*! Drop all types from the database. */
|
||||
virtual void dropAllTypes() const;
|
||||
|
||||
/*! Get all of the table names for the database. */
|
||||
virtual QSqlQuery getAllTables() const;
|
||||
/*! Get all of the view names for the database. */
|
||||
virtual QSqlQuery getAllViews() const;
|
||||
|
||||
/*! Enable foreign key constraints. */
|
||||
QSqlQuery enableForeignKeyConstraints() const;
|
||||
/*! Disable foreign key constraints. */
|
||||
QSqlQuery disableForeignKeyConstraints() const;
|
||||
|
||||
/*! Get the column listing for a given table. */
|
||||
virtual QStringList getColumnListing(const QString &table) const;
|
||||
|
||||
/*! Determine if the given table exists. */
|
||||
virtual bool hasTable(const QString &table) const;
|
||||
/*! Determine if the given table has a given column. */
|
||||
bool hasColumn(const QString &table, const QString &column) const;
|
||||
/*! Determine if the given table has given columns. */
|
||||
bool hasColumns(const QString &table, const QVector<QString> &columns) const;
|
||||
|
||||
/* Getters */
|
||||
/*! Get the database connection reference. */
|
||||
inline DatabaseConnection &getConnection();
|
||||
/*! Get the database connection reference, const version. */
|
||||
inline const DatabaseConnection &getConnection() const;
|
||||
|
||||
protected:
|
||||
using SchemaGrammar = Grammars::SchemaGrammar;
|
||||
|
||||
/*! Create a new command set with a Closure. */
|
||||
Blueprint
|
||||
createBlueprint(const QString &table,
|
||||
const std::function<void(Blueprint &)> &callback = nullptr) const;
|
||||
/*! Execute the blueprint to build / modify the table. */
|
||||
void build(Blueprint &&blueprint) const;
|
||||
|
||||
/*! The database connection instance. */
|
||||
DatabaseConnection &m_connection;
|
||||
/*! The schema grammar instance. */
|
||||
const SchemaGrammar &m_grammar;
|
||||
};
|
||||
|
||||
} // namespace Schema
|
||||
template<QStringConcept ...Args>
|
||||
void SchemaBuilder::dropColumns(const QString &table, Args &&...columns)
|
||||
{
|
||||
dropColumns(table, {std::forward<Args>(columns)...});
|
||||
}
|
||||
|
||||
DatabaseConnection &SchemaBuilder::getConnection()
|
||||
{
|
||||
return m_connection;
|
||||
}
|
||||
|
||||
const DatabaseConnection &SchemaBuilder::getConnection() const
|
||||
{
|
||||
return m_connection;
|
||||
}
|
||||
|
||||
} // namespace SchemaNs
|
||||
} // namespace Orm
|
||||
|
||||
TINYORM_END_COMMON_NAMESPACE
|
||||
|
||||
16
include/orm/schema/schemaconstants.hpp
Normal file
16
include/orm/schema/schemaconstants.hpp
Normal file
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
#ifndef ORM_SCHEMA_SCHEMACONSTANTS_HPP
|
||||
#define ORM_SCHEMA_SCHEMACONSTANTS_HPP
|
||||
|
||||
#include "orm/macros/systemheader.hpp"
|
||||
TINY_SYSTEM_HEADER
|
||||
|
||||
#include "orm/config.hpp"
|
||||
|
||||
#ifdef TINYORM_EXTERN_CONSTANTS
|
||||
# include "orm/schema/schemaconstants_extern.hpp"
|
||||
#else
|
||||
# include "orm/schema/schemaconstants_inline.hpp"
|
||||
#endif
|
||||
|
||||
#endif // ORM_SCHEMA_SCHEMACONSTANTS_HPP
|
||||
60
include/orm/schema/schemaconstants_extern.hpp
Normal file
60
include/orm/schema/schemaconstants_extern.hpp
Normal file
@@ -0,0 +1,60 @@
|
||||
#pragma once
|
||||
#ifndef ORM_SCHEMA_SCHEMACONSTANTS_EXTERN_HPP
|
||||
#define ORM_SCHEMA_SCHEMACONSTANTS_EXTERN_HPP
|
||||
|
||||
#include "orm/macros/systemheader.hpp"
|
||||
TINY_SYSTEM_HEADER
|
||||
|
||||
#include <QString>
|
||||
|
||||
#include "orm/macros/commonnamespace.hpp"
|
||||
#include "orm/macros/export.hpp"
|
||||
|
||||
TINYORM_BEGIN_COMMON_NAMESPACE
|
||||
|
||||
/*! Namespace constains common chars and strings used in the Schema. */
|
||||
namespace Orm::SchemaNs
|
||||
{
|
||||
namespace Constants
|
||||
{
|
||||
|
||||
// Command names
|
||||
SHAREDLIB_EXPORT extern const QString Create;
|
||||
SHAREDLIB_EXPORT extern const QString Add;
|
||||
SHAREDLIB_EXPORT extern const QString Change;
|
||||
SHAREDLIB_EXPORT extern const QString Rename;
|
||||
SHAREDLIB_EXPORT extern const QString Drop;
|
||||
SHAREDLIB_EXPORT extern const QString DropIfExists;
|
||||
SHAREDLIB_EXPORT extern const QString DropColumn;
|
||||
SHAREDLIB_EXPORT extern const QString RenameColumn;
|
||||
SHAREDLIB_EXPORT extern const QString DropPrimary;
|
||||
SHAREDLIB_EXPORT extern const QString DropUnique;
|
||||
SHAREDLIB_EXPORT extern const QString DropIndex;
|
||||
SHAREDLIB_EXPORT extern const QString DropFullText;
|
||||
SHAREDLIB_EXPORT extern const QString DropSpatialIndex;
|
||||
SHAREDLIB_EXPORT extern const QString DropForeign;
|
||||
SHAREDLIB_EXPORT extern const QString RenameIndex;
|
||||
|
||||
// Indexes
|
||||
SHAREDLIB_EXPORT extern const QString Primary;
|
||||
SHAREDLIB_EXPORT extern const QString Unique;
|
||||
SHAREDLIB_EXPORT extern const QString Index;
|
||||
SHAREDLIB_EXPORT extern const QString Fulltext;
|
||||
SHAREDLIB_EXPORT extern const QString SpatialIndex;
|
||||
SHAREDLIB_EXPORT extern const QString Foreign;
|
||||
|
||||
// Foreign constrains
|
||||
SHAREDLIB_EXPORT extern const QString Cascade;
|
||||
SHAREDLIB_EXPORT extern const QString Restrict;
|
||||
SHAREDLIB_EXPORT extern const QString SetNull;
|
||||
|
||||
} // namespace Constants
|
||||
|
||||
// NOLINTNEXTLINE(google-build-using-namespace)
|
||||
using namespace Orm::SchemaNs::Constants;
|
||||
|
||||
} // namespace Orm::SchemaNs
|
||||
|
||||
TINYORM_END_COMMON_NAMESPACE
|
||||
|
||||
#endif // ORM_SCHEMA_SCHEMACONSTANTS_EXTERN_HPP
|
||||
60
include/orm/schema/schemaconstants_inline.hpp
Normal file
60
include/orm/schema/schemaconstants_inline.hpp
Normal file
@@ -0,0 +1,60 @@
|
||||
#pragma once
|
||||
#ifndef ORM_SCHEMA_SCHEMACONSTANTS_INLINE_HPP
|
||||
#define ORM_SCHEMA_SCHEMACONSTANTS_INLINE_HPP
|
||||
|
||||
#include "orm/macros/systemheader.hpp"
|
||||
TINY_SYSTEM_HEADER
|
||||
|
||||
#include <QString>
|
||||
|
||||
#include "orm/macros/commonnamespace.hpp"
|
||||
|
||||
TINYORM_BEGIN_COMMON_NAMESPACE
|
||||
|
||||
/*! Namespace constains common chars and strings used in the Schema. */
|
||||
namespace Orm::SchemaNs
|
||||
{
|
||||
namespace Constants
|
||||
{
|
||||
|
||||
// Command names
|
||||
inline const QString Create = QStringLiteral("create");
|
||||
inline const QString Add = QStringLiteral("add");
|
||||
inline const QString Change = QStringLiteral("change");
|
||||
inline const QString Drop = QStringLiteral("drop");
|
||||
inline const QString DropIfExists = QStringLiteral("dropIfExists");
|
||||
inline const QString Rename = QStringLiteral("rename");
|
||||
inline const QString DropColumn = QStringLiteral("dropColumn");
|
||||
inline const QString RenameColumn = QStringLiteral("renameColumn");
|
||||
inline const QString DropPrimary = QStringLiteral("dropPrimary");
|
||||
inline const QString DropUnique = QStringLiteral("dropUnique");
|
||||
inline const QString DropIndex = QStringLiteral("dropIndex");
|
||||
inline const QString DropFullText = QStringLiteral("dropFullText");
|
||||
inline const QString DropSpatialIndex = QStringLiteral("dropSpatialIndex");
|
||||
inline const QString DropForeign = QStringLiteral("dropForeign");
|
||||
inline const QString RenameIndex = QStringLiteral("renameIndex");
|
||||
|
||||
// Indexes
|
||||
inline const QString Primary = QStringLiteral("primary");
|
||||
inline const QString Unique = QStringLiteral("unique");
|
||||
inline const QString Index = QStringLiteral("index");
|
||||
// CUR schema, I fucked up case in fulltext and spatialIndex during replacement, have to check all occurences :( silverqx
|
||||
inline const QString Fulltext = QStringLiteral("fulltext");
|
||||
inline const QString SpatialIndex = QStringLiteral("spatialIndex");
|
||||
inline const QString Foreign = QStringLiteral("foreign");
|
||||
|
||||
// Foreign constrains
|
||||
inline const QString Cascade = QStringLiteral("cascade");
|
||||
inline const QString Restrict = QStringLiteral("restrict");
|
||||
inline const QString SetNull = QStringLiteral("set null");
|
||||
|
||||
} // namespace Constants
|
||||
|
||||
// NOLINTNEXTLINE(google-build-using-namespace)
|
||||
using namespace Orm::SchemaNs::Constants;
|
||||
|
||||
} // namespace Orm::SchemaNs
|
||||
|
||||
TINYORM_END_COMMON_NAMESPACE
|
||||
|
||||
#endif // ORM_SCHEMA_SCHEMACONSTANTS_INLINE_HPP
|
||||
80
include/orm/schema/schematypes.hpp
Normal file
80
include/orm/schema/schematypes.hpp
Normal file
@@ -0,0 +1,80 @@
|
||||
#pragma once
|
||||
#ifndef ORM_SCHEMATYPES_HPP
|
||||
#define ORM_SCHEMATYPES_HPP
|
||||
|
||||
#include "orm/macros/systemheader.hpp"
|
||||
TINY_SYSTEM_HEADER
|
||||
|
||||
#include <QString>
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "orm/macros/commonnamespace.hpp"
|
||||
|
||||
TINYORM_BEGIN_COMMON_NAMESPACE
|
||||
|
||||
namespace Orm::SchemaNs
|
||||
{
|
||||
|
||||
/*! Default string/char length. */
|
||||
inline constexpr int DefaultStringLength = 255;
|
||||
|
||||
/*! Column types. */
|
||||
enum struct ColumnType
|
||||
{
|
||||
Char,
|
||||
String,
|
||||
TinyText,
|
||||
Text,
|
||||
MediumText,
|
||||
LongText,
|
||||
BigInteger,
|
||||
Integer,
|
||||
MediumInteger,
|
||||
TinyInteger,
|
||||
SmallInteger,
|
||||
Float,
|
||||
Double,
|
||||
Decimal,
|
||||
Real, // PostgreSQL only
|
||||
Boolean,
|
||||
Enum,
|
||||
Set, // MySQL only
|
||||
Json,
|
||||
Jsonb,
|
||||
Date,
|
||||
DateTime,
|
||||
DateTimeTz,
|
||||
Time,
|
||||
TimeTz,
|
||||
Timestamp,
|
||||
TimestampTz,
|
||||
Year,
|
||||
Binary,
|
||||
Uuid,
|
||||
IpAddress,
|
||||
MacAddress,
|
||||
Geometry,
|
||||
Point,
|
||||
LineString,
|
||||
Polygon,
|
||||
GeometryCollection,
|
||||
MultiPoint,
|
||||
MultiLineString,
|
||||
MultiPolygon,
|
||||
MultiPolygonZ, // PostgreSQL only
|
||||
Computed, // SqlServer only
|
||||
};
|
||||
|
||||
/*! Auto increment value for a column. */
|
||||
struct AutoIncrementColumnValue
|
||||
{
|
||||
QString columnName;
|
||||
std::optional<quint64> value;
|
||||
};
|
||||
|
||||
} // namespace Orm::SchemaNs
|
||||
|
||||
TINYORM_END_COMMON_NAMESPACE
|
||||
|
||||
#endif // ORM_SCHEMATYPES_HPP
|
||||
@@ -9,10 +9,10 @@ TINY_SYSTEM_HEADER
|
||||
|
||||
TINYORM_BEGIN_COMMON_NAMESPACE
|
||||
|
||||
namespace Orm::Schema
|
||||
namespace Orm::SchemaNs
|
||||
{
|
||||
|
||||
/*! SQLite schema repository class. */
|
||||
/*! SQLite schema builder class. */
|
||||
class SQLiteSchemaBuilder : public SchemaBuilder
|
||||
{
|
||||
Q_DISABLE_COPY(SQLiteSchemaBuilder)
|
||||
@@ -25,7 +25,7 @@ namespace Orm::Schema
|
||||
inline ~SQLiteSchemaBuilder() override = default;
|
||||
};
|
||||
|
||||
} // namespace Orm::Schema
|
||||
} // namespace Orm::SchemaNs
|
||||
|
||||
TINYORM_END_COMMON_NAMESPACE
|
||||
|
||||
|
||||
@@ -654,7 +654,7 @@ namespace Private
|
||||
template<typename Related>
|
||||
void QueriesRelationships<Model>::createHasNestedStore(
|
||||
const QString &comparison, const qint64 count,
|
||||
const std::function<void (TinyBuilder<Related> &)> &callback) const
|
||||
const std::function<void(TinyBuilder<Related> &)> &callback) const
|
||||
{
|
||||
// BUG clang doesn't know how to init. aggregate ( by forward declaration inside, using construct in place ) silverqx
|
||||
#ifdef __clang__
|
||||
|
||||
@@ -44,7 +44,8 @@ namespace Orm::Tiny
|
||||
public Tiny::Concerns::GuardsAttributes<Derived, AllRelations...>,
|
||||
public Tiny::Concerns::HasRelationships<Derived, AllRelations...>,
|
||||
public Tiny::Concerns::HasTimestamps<Derived, AllRelations...>,
|
||||
public ModelProxies<Derived, AllRelations...>
|
||||
public ModelProxies<Derived, AllRelations...>,
|
||||
public IsModel
|
||||
{
|
||||
// To access getUserXx() methods
|
||||
friend Concerns::GuardsAttributes<Derived, AllRelations...>;
|
||||
@@ -1320,3 +1321,5 @@ TINYORM_END_COMMON_NAMESPACE
|
||||
// CUR Belongs To Many firstOrNew, firstOrCreate, and updateOrCreate Methods, revisit first and second argument silverqx
|
||||
// CUR add attribute to touch() method silverqx
|
||||
// SEC fix LoadLibrary() before qsql plugin loads? https://www.qt.io/blog/security-advisory-qlockfile-qauthenticator-windows-platform-plugin silverqx
|
||||
// CUR1 connection, control disable/enable logging at runtime silverqx
|
||||
// CUR cmake, make TinyUtils_target in TinyTestCommon.cmake optional, not always needed to link to silverqx
|
||||
|
||||
@@ -906,7 +906,7 @@ namespace Orm::Tiny
|
||||
// template<typename ...Args>
|
||||
// Builder<Model> &
|
||||
// Builder<Model>::callScope(
|
||||
// const std::function<void (Builder &, Args ...)> &scope,
|
||||
// const std::function<void(Builder &, Args ...)> &scope,
|
||||
// Args &&...parameters)
|
||||
// {
|
||||
// std::invoke(scope, *this, std::forward<Args>(parameters)...);
|
||||
|
||||
@@ -19,6 +19,12 @@ namespace Orm::Tiny
|
||||
template<typename Derived, typename ...AllRelations>
|
||||
concept AllRelationsConcept = (!std::same_as<Derived, AllRelations> && ...);
|
||||
|
||||
class IsModel;
|
||||
|
||||
/*! Concept to check whether a passed type is the model class. */
|
||||
template<typename T>
|
||||
concept ModelConcept = std::derived_from<T, IsModel>;
|
||||
|
||||
} // namespace Orm::Tiny
|
||||
|
||||
TINYORM_END_COMMON_NAMESPACE
|
||||
|
||||
@@ -73,6 +73,10 @@ namespace Tiny
|
||||
bool touch = true;
|
||||
};
|
||||
|
||||
/*! The tag for the model. */
|
||||
class IsModel
|
||||
{};
|
||||
|
||||
namespace Concerns
|
||||
{
|
||||
/*! QueriesRelationships builder type passed to the callback. */
|
||||
|
||||
59
include/orm/utils/container.hpp
Normal file
59
include/orm/utils/container.hpp
Normal file
@@ -0,0 +1,59 @@
|
||||
#pragma once
|
||||
#ifndef ORM_UTILS_CONTAINER_HPP
|
||||
#define ORM_UTILS_CONTAINER_HPP
|
||||
|
||||
#include "orm/macros/systemheader.hpp"
|
||||
TINY_SYSTEM_HEADER
|
||||
|
||||
#include "orm/constants.hpp"
|
||||
#include "orm/ormconcepts.hpp"
|
||||
|
||||
TINYORM_BEGIN_COMMON_NAMESPACE
|
||||
|
||||
namespace Orm::Utils
|
||||
{
|
||||
|
||||
/*! Containers related library class. */
|
||||
class Container
|
||||
{
|
||||
Q_DISABLE_COPY(Container)
|
||||
|
||||
public:
|
||||
/*! Deleted default constructor, this is a pure library class. */
|
||||
Container() = delete;
|
||||
/*! Deleted destructor. */
|
||||
~Container() = delete;
|
||||
|
||||
/*! Convert a string container into a (comma) delimited string. */
|
||||
template<ColumnContainer T, DelimiterConcept D = const QString &>
|
||||
static QString
|
||||
join(const T &container, D &&delimiter = Constants::COMMA);
|
||||
};
|
||||
|
||||
template<ColumnContainer T, DelimiterConcept D>
|
||||
QString Container::join(const T &container, D &&delimiter)
|
||||
{
|
||||
QString columnized;
|
||||
// Estimate a size to avoid resizing, 7 for an item and 2 for the delimiter
|
||||
columnized.reserve(container.size() * (7 + 2));
|
||||
|
||||
if (container.isEmpty())
|
||||
return columnized;
|
||||
|
||||
const auto end = container.cend() - 1;
|
||||
auto it = container.begin();
|
||||
|
||||
for (; it < end; ++it)
|
||||
columnized += Constants::NOSPACE.arg(*it).arg(std::forward<D>(delimiter));
|
||||
|
||||
if (it == end)
|
||||
columnized += *it;
|
||||
|
||||
return columnized;
|
||||
}
|
||||
|
||||
} // namespace Orm::Utils
|
||||
|
||||
TINYORM_END_COMMON_NAMESPACE
|
||||
|
||||
#endif // ORM_UTILS_CONTAINER_HPP
|
||||
@@ -15,10 +15,10 @@ namespace Orm
|
||||
parametrize uses Container type and Parametrize constraint.
|
||||
columnize() is used for column names containers (constrained by ColumnContainer
|
||||
concept) and it calls wrapArray() internally, columnize uses ColumnContainer
|
||||
constraint.
|
||||
constraint, it converts a vector of column names into a wrapped comma delimited string.
|
||||
Values or columns/tables/identifiers can also be the Query::Expression.
|
||||
The Query::Expression is always converted to the QString and appended to the query.
|
||||
quoteString() can be used to quote string literals, it is not used anywhere for now.
|
||||
quoteString() can be used to quote string literals.
|
||||
*/
|
||||
|
||||
const QString &BaseGrammar::getDateFormat() const
|
||||
@@ -57,7 +57,7 @@ QString BaseGrammar::wrap(const Column &value) const
|
||||
// NOLINTNEXTLINE(misc-no-recursion)
|
||||
QString BaseGrammar::wrapTable(const QString &table) const
|
||||
{
|
||||
return wrap(QStringLiteral("%1%2").arg(m_tablePrefix, table), true);
|
||||
return wrap(NOSPACE.arg(m_tablePrefix, table), true);
|
||||
}
|
||||
|
||||
QString BaseGrammar::wrapTable(const FromClause &table) const
|
||||
@@ -106,6 +106,8 @@ QString BaseGrammar::unqualifyColumn(const QString &column) const
|
||||
return column.split(DOT).last().trimmed();
|
||||
}
|
||||
|
||||
/* protected */
|
||||
|
||||
QString BaseGrammar::parameter(const QVariant &value) const
|
||||
{
|
||||
return isExpression(value) ? getValue(value).value<QString>()
|
||||
@@ -121,7 +123,7 @@ QString BaseGrammar::wrapAliasedValue(const QString &value, const bool prefixAli
|
||||
as well in order to generate proper syntax. If this is a column of course
|
||||
no prefix is necessary. The condition will be true when from wrapTable. */
|
||||
if (prefixAlias)
|
||||
segments[1] = QStringLiteral("%1%2").arg(m_tablePrefix, segments[1]);
|
||||
segments[1] = NOSPACE.arg(m_tablePrefix, segments[1]);
|
||||
|
||||
return QStringLiteral("%1 as %2").arg(wrap(segments[0]), wrapValue(segments[1]));
|
||||
}
|
||||
@@ -179,25 +181,6 @@ QString BaseGrammar::getAliasFromFrom(const QString &from) const
|
||||
return segments.last();
|
||||
}
|
||||
|
||||
QString BaseGrammar::columnizeInternal(const QVector<QString> &columns) const
|
||||
{
|
||||
QString columnized;
|
||||
|
||||
if (columns.isEmpty())
|
||||
return columnized;
|
||||
|
||||
const auto end = columns.cend() - 1;
|
||||
auto it = columns.begin();
|
||||
|
||||
for (; it < end; ++it)
|
||||
columnized += QStringLiteral("%1, ").arg(*it);
|
||||
|
||||
if (it == end)
|
||||
columnized += *it;
|
||||
|
||||
return columnized;
|
||||
}
|
||||
|
||||
} // namespace Orm
|
||||
|
||||
TINYORM_END_COMMON_NAMESPACE
|
||||
|
||||
@@ -63,6 +63,11 @@ ConnectionFactory::parseConfig(QVariantHash &config, const QString &name) const
|
||||
if (!config.contains(options_))
|
||||
config.insert(options_, QVariantHash());
|
||||
|
||||
if (!config.contains(prefix_indexes))
|
||||
config.insert(prefix_indexes, false);
|
||||
|
||||
// FUTURE connector, this can be enhanced, eg. add default values per driver, eg. engine_ for mysql is missing, can not be added because is driver specific silverqx
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
#include <QRegularExpression>
|
||||
#include <QtSql/QSqlQuery>
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
#include "orm/constants.hpp"
|
||||
#include "orm/exceptions/queryerror.hpp"
|
||||
#include "orm/utils/type.hpp"
|
||||
@@ -85,11 +87,12 @@ void PostgresConnector::configureTimezone(const QSqlDatabase &connection,
|
||||
|
||||
QSqlQuery query(connection);
|
||||
|
||||
static const QStringList local {"local", "default"};
|
||||
static const std::unordered_set<QString> local {QStringLiteral("local"),
|
||||
QStringLiteral("default")};
|
||||
|
||||
const auto timezone = config[timezone_].value<QString>();
|
||||
|
||||
if (local.contains(timezone, Qt::CaseInsensitive)) {
|
||||
if (local.contains(timezone.toLower())) {
|
||||
if (query.exec(QStringLiteral("set time zone %1").arg(timezone)))
|
||||
return;
|
||||
} else
|
||||
|
||||
@@ -38,6 +38,8 @@ namespace Orm::Constants
|
||||
const QString UPDATED_AT = QStringLiteral("updated_at");
|
||||
const QString PARENTH_ONE = QStringLiteral("(%1)");
|
||||
const QString NEWLINE = QStringLiteral("\n");
|
||||
const QString SPACE_IN = QStringLiteral("%1 %2");
|
||||
const QString NOSPACE = QStringLiteral("%1%2");
|
||||
|
||||
const QString QMYSQL = QStringLiteral("QMYSQL");
|
||||
const QString QPSQL = QStringLiteral("QPSQL");
|
||||
@@ -59,10 +61,12 @@ namespace Orm::Constants
|
||||
const QString prefix_ = QStringLiteral("prefix");
|
||||
const QString options_ = QStringLiteral("options");
|
||||
const QString strict_ = QStringLiteral("strict");
|
||||
const QString engine_ = QStringLiteral("engine");
|
||||
|
||||
const QString isolation_level = QStringLiteral("isolation_level");
|
||||
const QString foreign_key_constraints = QStringLiteral("foreign_key_constraints");
|
||||
const QString check_database_exists = QStringLiteral("check_database_exists");
|
||||
const QString prefix_indexes = QStringLiteral("prefix_indexes");
|
||||
|
||||
const QString H127001 = QStringLiteral("127.0.0.1");
|
||||
const QString LOCALHOST = QStringLiteral("localhost");
|
||||
@@ -75,6 +79,10 @@ namespace Orm::Constants
|
||||
const QString PUBLIC = QStringLiteral("public");
|
||||
const QString UTF8 = QStringLiteral("utf8");
|
||||
const QString UTF8MB4 = QStringLiteral("utf8mb4");
|
||||
const QString InnoDB = QStringLiteral("InnoDB");
|
||||
const QString MyISAM = QStringLiteral("MyISAM");
|
||||
|
||||
const QString NotImplemented = QStringLiteral("Not implemented :/.");
|
||||
|
||||
// Comparison/logical/search operators
|
||||
const QString EQ = QStringLiteral("=");
|
||||
|
||||
@@ -367,6 +367,11 @@ bool DatabaseConnection::pingDatabase()
|
||||
.arg(driverName()));
|
||||
}
|
||||
|
||||
QSqlDriver *DatabaseConnection::driver()
|
||||
{
|
||||
return getQtConnection().driver();
|
||||
}
|
||||
|
||||
void DatabaseConnection::reconnect() const
|
||||
{
|
||||
if (!m_reconnector)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "orm/concerns/hasconnectionresolver.hpp"
|
||||
#include "orm/exceptions/invalidargumenterror.hpp"
|
||||
#include "orm/schema.hpp"
|
||||
|
||||
TINYORM_BEGIN_COMMON_NAMESPACE
|
||||
|
||||
@@ -213,6 +214,11 @@ bool DatabaseManager::pingDatabase(const QString &connection)
|
||||
return this->connection(connection).pingDatabase();
|
||||
}
|
||||
|
||||
QSqlDriver *DatabaseManager::driver(const QString &connection)
|
||||
{
|
||||
return this->connection(connection).driver();
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
const auto *const InstanceExceptionMessage =
|
||||
@@ -312,10 +318,14 @@ bool DatabaseManager::removeConnection(const QString &name)
|
||||
if ((*m_connections).erase(name_) == 0)
|
||||
return false;
|
||||
|
||||
// Remove a cached schema builder for the currently removing connection
|
||||
if (Schema::m_schemaBuildersCache.contains(name_))
|
||||
Schema::m_schemaBuildersCache.erase(name_);
|
||||
|
||||
// Remove TinyORM configuration
|
||||
(*m_configuration).remove(name_);
|
||||
// Remove Qt's database connection
|
||||
QSqlDatabase::removeDatabase(name_);
|
||||
// Also remove configuration
|
||||
(*m_configuration).remove(name_);
|
||||
|
||||
resetDefaultConnection_();
|
||||
|
||||
|
||||
@@ -247,6 +247,11 @@ bool DB::pingDatabase(const QString &connection)
|
||||
return manager().connection(connection).pingDatabase();
|
||||
}
|
||||
|
||||
QSqlDriver *DB::driver(const QString &connection)
|
||||
{
|
||||
return manager().connection(connection).driver();
|
||||
}
|
||||
|
||||
bool DB::countingElapsed(const QString &connection)
|
||||
{
|
||||
return manager().connection(connection).countingElapsed();
|
||||
|
||||
@@ -50,7 +50,7 @@ std::unique_ptr<SchemaBuilder> MySqlConnection::getSchemaBuilder()
|
||||
if (!m_schemaGrammar)
|
||||
useDefaultSchemaGrammar();
|
||||
|
||||
return std::make_unique<Schema::MySqlSchemaBuilder>(*this);
|
||||
return std::make_unique<SchemaNs::MySqlSchemaBuilder>(*this);
|
||||
}
|
||||
|
||||
bool MySqlConnection::isMaria()
|
||||
@@ -146,7 +146,7 @@ std::unique_ptr<QueryGrammar> MySqlConnection::getDefaultQueryGrammar() const
|
||||
std::unique_ptr<SchemaGrammar> MySqlConnection::getDefaultSchemaGrammar() const
|
||||
{
|
||||
// Ownership of a unique_ptr()
|
||||
auto grammar = std::make_unique<Schema::Grammars::MySqlSchemaGrammar>();
|
||||
auto grammar = std::make_unique<SchemaNs::Grammars::MySqlSchemaGrammar>();
|
||||
|
||||
withTablePrefix(*grammar);
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ std::unique_ptr<SchemaBuilder> PostgresConnection::getSchemaBuilder()
|
||||
if (!m_schemaGrammar)
|
||||
useDefaultSchemaGrammar();
|
||||
|
||||
return std::make_unique<Schema::PostgresSchemaBuilder>(*this);
|
||||
return std::make_unique<SchemaNs::PostgresSchemaBuilder>(*this);
|
||||
}
|
||||
|
||||
std::unique_ptr<QueryGrammar> PostgresConnection::getDefaultQueryGrammar() const
|
||||
@@ -48,7 +48,7 @@ std::unique_ptr<QueryGrammar> PostgresConnection::getDefaultQueryGrammar() const
|
||||
std::unique_ptr<SchemaGrammar> PostgresConnection::getDefaultSchemaGrammar() const
|
||||
{
|
||||
// Ownership of a unique_ptr()
|
||||
auto grammar = std::make_unique<Schema::Grammars::PostgresSchemaGrammar>();
|
||||
auto grammar = std::make_unique<SchemaNs::Grammars::PostgresSchemaGrammar>();
|
||||
|
||||
withTablePrefix(*grammar);
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ QString Grammar::compileInsert(const QueryBuilder &query,
|
||||
table,
|
||||
// Columns are obtained only from a first QMap
|
||||
columnize(values.at(0).keys()),
|
||||
compileInsertToVector(values).join(COMMA));
|
||||
columnizeWithoutWrap(compileInsertToVector(values)));
|
||||
}
|
||||
|
||||
QString Grammar::compileInsertOrIgnore(const QueryBuilder &/*unused*/,
|
||||
@@ -152,8 +152,9 @@ QStringList Grammar::compileComponents(const QueryBuilder &query) const
|
||||
{
|
||||
QStringList sql;
|
||||
|
||||
const auto &compileMap = getCompileMap();
|
||||
for (const auto &component : compileMap)
|
||||
for (const auto &compileMap = getCompileMap();
|
||||
const auto &component : compileMap
|
||||
)
|
||||
if (component.isset)
|
||||
if (component.isset(query))
|
||||
sql.append(std::invoke(component.compileMethod, query));
|
||||
@@ -227,9 +228,8 @@ QStringList Grammar::compileWheresToVector(const QueryBuilder &query) const
|
||||
compiledWheres.reserve(wheres.size());
|
||||
|
||||
for (const auto &where : wheres)
|
||||
compiledWheres << QStringLiteral("%1 %2")
|
||||
.arg(where.condition,
|
||||
std::invoke(getWhereMethod(where.type), where));
|
||||
compiledWheres << SPACE_IN.arg(where.condition,
|
||||
std::invoke(getWhereMethod(where.type), where));
|
||||
|
||||
return compiledWheres;
|
||||
}
|
||||
@@ -242,8 +242,7 @@ QString Grammar::concatenateWhereClauses(const QueryBuilder &query,
|
||||
? QStringLiteral("where")
|
||||
: QStringLiteral("on");
|
||||
|
||||
return QStringLiteral("%1 %2").arg(conjunction,
|
||||
removeLeadingBoolean(sql.join(SPACE)));
|
||||
return SPACE_IN.arg(conjunction, removeLeadingBoolean(sql.join(SPACE)));
|
||||
}
|
||||
|
||||
QString Grammar::compileJoins(const QueryBuilder &query) const
|
||||
@@ -292,7 +291,7 @@ QString Grammar::compileHaving(const HavingConditionItem &having) const
|
||||
|
||||
T_UNLIKELY
|
||||
case HavingType::RAW:
|
||||
return QStringLiteral("%1 %2").arg(having.condition, having.sql);
|
||||
return SPACE_IN.arg(having.condition, having.sql);
|
||||
|
||||
T_UNLIKELY
|
||||
default:
|
||||
@@ -312,7 +311,8 @@ QString Grammar::compileOrders(const QueryBuilder &query) const
|
||||
if (query.getOrders().isEmpty())
|
||||
return QLatin1String("");
|
||||
|
||||
return QStringLiteral("order by %1").arg(compileOrdersToVector(query).join(COMMA));
|
||||
return QStringLiteral("order by %1")
|
||||
.arg(columnizeWithoutWrap(compileOrdersToVector(query)));
|
||||
}
|
||||
|
||||
QStringList Grammar::compileOrdersToVector(const QueryBuilder &query) const
|
||||
@@ -324,8 +324,8 @@ QStringList Grammar::compileOrdersToVector(const QueryBuilder &query) const
|
||||
|
||||
for (const auto &order : orders)
|
||||
if (order.sql.isEmpty()) T_LIKELY
|
||||
compiledOrders << QStringLiteral("%1 %2")
|
||||
.arg(wrap(order.column), order.direction.toLower());
|
||||
compiledOrders << SPACE_IN.arg(wrap(order.column),
|
||||
order.direction.toLower());
|
||||
else T_UNLIKELY
|
||||
compiledOrders << order.sql;
|
||||
|
||||
@@ -450,7 +450,7 @@ Grammar::compileUpdateColumns(const QVector<UpdateItem> &values) const
|
||||
wrap(assignment.column),
|
||||
parameter(assignment.value));
|
||||
|
||||
return compiledAssignments.join(COMMA);
|
||||
return columnizeWithoutWrap(compiledAssignments);
|
||||
}
|
||||
|
||||
QString
|
||||
|
||||
@@ -92,6 +92,7 @@ QString MySqlGrammar::wrapValue(QString value) const
|
||||
const QMap<Grammar::SelectComponentType, Grammar::SelectComponentValue> &
|
||||
MySqlGrammar::getCompileMap() const
|
||||
{
|
||||
// CUR schema, update all this comments silverqx
|
||||
/* Needed, because some compileXx() methods are overloaded, this way I will capture
|
||||
'this' reference and the compileMethod rvalue reference in the following lambda
|
||||
and simply save std::function<> in the SelectComponentValue's compileMethod data
|
||||
|
||||
@@ -92,7 +92,7 @@ QString PostgresGrammar::compileUpdateColumns(const QVector<UpdateItem> &values)
|
||||
wrap(unqualifyColumn(assignment.column)),
|
||||
parameter(assignment.value));
|
||||
|
||||
return compiledAssignments.join(COMMA);
|
||||
return columnizeWithoutWrap(compiledAssignments);
|
||||
}
|
||||
|
||||
const QMap<Grammar::SelectComponentType, Grammar::SelectComponentValue> &
|
||||
|
||||
@@ -69,7 +69,7 @@ QString SQLiteGrammar::compileUpdateColumns(const QVector<UpdateItem> &values) c
|
||||
wrap(unqualifyColumn(assignment.column)),
|
||||
parameter(assignment.value));
|
||||
|
||||
return compiledAssignments.join(COMMA);
|
||||
return columnizeWithoutWrap(compiledAssignments);
|
||||
}
|
||||
|
||||
const QMap<Grammar::SelectComponentType, Grammar::SelectComponentValue> &
|
||||
|
||||
178
src/orm/schema.cpp
Normal file
178
src/orm/schema.cpp
Normal file
@@ -0,0 +1,178 @@
|
||||
#include "orm/schema.hpp"
|
||||
|
||||
#include "orm/macros/likely.hpp"
|
||||
#include "orm/schema/schemabuilder.hpp"
|
||||
|
||||
TINYORM_BEGIN_COMMON_NAMESPACE
|
||||
|
||||
namespace Orm
|
||||
{
|
||||
|
||||
std::unordered_map<Connectors::ConnectionName,
|
||||
std::unique_ptr<SchemaBuilder>> Schema::m_schemaBuildersCache;
|
||||
std::shared_ptr<DatabaseManager> Schema::m_manager;
|
||||
|
||||
/* public */
|
||||
|
||||
/* Proxy methods to the SchemaBuilder */
|
||||
|
||||
QSqlQuery Schema::createDatabase(const QString &name, const QString &connection)
|
||||
{
|
||||
return schemaBuilder(connection).createDatabase(name);
|
||||
}
|
||||
|
||||
QSqlQuery Schema::dropDatabaseIfExists(const QString &name, const QString &connection)
|
||||
{
|
||||
return schemaBuilder(connection).dropDatabaseIfExists(name);
|
||||
}
|
||||
|
||||
void Schema::create(
|
||||
const QString &table, const std::function<void(Blueprint &)> &callback,
|
||||
const QString &connection)
|
||||
{
|
||||
schemaBuilder(connection).create(table, callback);
|
||||
}
|
||||
|
||||
void Schema::table(
|
||||
const QString &table, const std::function<void(Blueprint &)> &callback,
|
||||
const QString &connection)
|
||||
{
|
||||
schemaBuilder(connection).table(table, callback);
|
||||
}
|
||||
|
||||
void Schema::drop(const QString &table, const QString &connection)
|
||||
{
|
||||
schemaBuilder(connection).drop(table);
|
||||
}
|
||||
|
||||
void Schema::dropIfExists(const QString &table, const QString &connection)
|
||||
{
|
||||
schemaBuilder(connection).dropIfExists(table);
|
||||
}
|
||||
|
||||
void Schema::rename(const QString &from, const QString &to, const QString &connection)
|
||||
{
|
||||
schemaBuilder(connection).rename(from, to);
|
||||
}
|
||||
|
||||
void Schema::dropColumns(const QString &table, const QVector<QString> &columns,
|
||||
const QString &connection)
|
||||
{
|
||||
schemaBuilder(connection).dropColumns(table, columns);
|
||||
}
|
||||
|
||||
void Schema::dropColumn(const QString &table, const QString &column,
|
||||
const QString &connection)
|
||||
{
|
||||
schemaBuilder(connection).dropColumns(table, {column});
|
||||
}
|
||||
|
||||
void Schema::renameColumn(const QString &table, const QString &from,
|
||||
const QString &to, const QString &connection)
|
||||
{
|
||||
schemaBuilder(connection).renameColumn(table, from, to);
|
||||
}
|
||||
|
||||
void Schema::dropAllTables(const QString &connection)
|
||||
{
|
||||
schemaBuilder(connection).dropAllTables();
|
||||
}
|
||||
|
||||
void Schema::dropAllViews(const QString &connection)
|
||||
{
|
||||
schemaBuilder(connection).dropAllViews();
|
||||
}
|
||||
|
||||
void Schema::dropAllTypes(const QString &connection)
|
||||
{
|
||||
schemaBuilder(connection).dropAllTypes();
|
||||
}
|
||||
|
||||
QSqlQuery Schema::getAllTables(const QString &connection)
|
||||
{
|
||||
return schemaBuilder(connection).getAllTables();
|
||||
}
|
||||
|
||||
QSqlQuery Schema::getAllViews(const QString &connection)
|
||||
{
|
||||
return schemaBuilder(connection).getAllViews();
|
||||
}
|
||||
|
||||
QSqlQuery Schema::enableForeignKeyConstraints(const QString &connection)
|
||||
{
|
||||
return schemaBuilder(connection).enableForeignKeyConstraints();
|
||||
}
|
||||
|
||||
QSqlQuery Schema::disableForeignKeyConstraints(const QString &connection)
|
||||
{
|
||||
return schemaBuilder(connection).disableForeignKeyConstraints();
|
||||
}
|
||||
|
||||
QStringList Schema::getColumnListing(const QString &table, const QString &connection)
|
||||
{
|
||||
return schemaBuilder(connection).getColumnListing(table);
|
||||
}
|
||||
|
||||
bool Schema::hasTable(const QString &table, const QString &connection)
|
||||
{
|
||||
return schemaBuilder(connection).hasTable(table);
|
||||
}
|
||||
|
||||
bool Schema::hasColumn(const QString &table, const QString &column,
|
||||
const QString &connection)
|
||||
{
|
||||
return schemaBuilder(connection).hasColumn(table, column);
|
||||
}
|
||||
|
||||
bool Schema::hasColumns(const QString &table, const QVector<QString> &columns,
|
||||
const QString &connection)
|
||||
{
|
||||
return schemaBuilder(connection).hasColumns(table, columns);
|
||||
}
|
||||
|
||||
/* Schema */
|
||||
|
||||
SchemaBuilder &Schema::connection(const QString &name)
|
||||
{
|
||||
return schemaBuilder(name);
|
||||
}
|
||||
|
||||
SchemaBuilder &Schema::on(const QString &name)
|
||||
{
|
||||
return schemaBuilder(name);
|
||||
}
|
||||
|
||||
/* Others */
|
||||
|
||||
void Schema::defaultStringLength(const int length)
|
||||
{
|
||||
Blueprint::defaultStringLength(length);
|
||||
}
|
||||
|
||||
/* private */
|
||||
|
||||
SchemaBuilder &Schema::schemaBuilder(const QString &connection)
|
||||
{
|
||||
/* Cache obtained schema builders, they should always be the same for the given
|
||||
connection name, cached value is removed from the cache in
|
||||
DatabaseManager::removeConnection() */
|
||||
if (m_schemaBuildersCache.contains(connection))
|
||||
return *m_schemaBuildersCache[connection];
|
||||
|
||||
// Ownership of a unique_ptr()
|
||||
return *(m_schemaBuildersCache[connection] = manager().connection(connection)
|
||||
.getSchemaBuilder());
|
||||
}
|
||||
|
||||
DatabaseManager &Schema::manager()
|
||||
{
|
||||
if (m_manager) T_LIKELY
|
||||
return *m_manager;
|
||||
|
||||
else T_UNLIKELY
|
||||
return *(m_manager = DatabaseManager::instance());
|
||||
}
|
||||
|
||||
} // namespace Orm
|
||||
|
||||
TINYORM_END_COMMON_NAMESPACE
|
||||
733
src/orm/schema/blueprint.cpp
Normal file
733
src/orm/schema/blueprint.cpp
Normal file
@@ -0,0 +1,733 @@
|
||||
#include "orm/schema/blueprint.hpp"
|
||||
|
||||
#include <range/v3/action/remove_if.hpp>
|
||||
#include <range/v3/algorithm/contains.hpp>
|
||||
#include <range/v3/view/filter.hpp>
|
||||
|
||||
#include "orm/databaseconnection.hpp"
|
||||
|
||||
TINYORM_BEGIN_COMMON_NAMESPACE
|
||||
|
||||
namespace Orm::SchemaNs
|
||||
{
|
||||
|
||||
/* public */
|
||||
|
||||
int Blueprint::DefaultStringLength = SchemaNs::DefaultStringLength;
|
||||
|
||||
Blueprint::Blueprint(
|
||||
QString table, const std::function<void(Blueprint &)> &callback,
|
||||
QString &&prefix
|
||||
)
|
||||
: m_table(std::move(table))
|
||||
, m_prefix(std::move(prefix))
|
||||
{
|
||||
/* Pretty sure that there will be at least 2 columns and 1-2 commands, so reserve
|
||||
some memory to avoid resizing. */
|
||||
m_columns.reserve(4);
|
||||
m_commands.reserve(3);
|
||||
|
||||
if (callback)
|
||||
std::invoke(callback, *this);
|
||||
}
|
||||
|
||||
void Blueprint::build(DatabaseConnection &connection, const SchemaGrammar &grammar)
|
||||
{
|
||||
// TODO clazy, old clazy check range-loop, remove after ugprade to newer clazy (1.11) silverqx
|
||||
for (const auto &queryString : toSql(connection, grammar)) // clazy:exclude=range-loop,range-loop-detach
|
||||
connection.statement(queryString);
|
||||
}
|
||||
|
||||
QVector<QString> Blueprint::toSql(const DatabaseConnection &connection,
|
||||
const SchemaGrammar &grammar)
|
||||
{
|
||||
addImpliedCommands(grammar);
|
||||
|
||||
// FUTURE schema, sqlite silverqx
|
||||
/* Each type of command has a corresponding compiler function on the schema
|
||||
grammar which is used to build the necessary SQL statements to build
|
||||
the blueprint element, so we'll just call that compilers function. */
|
||||
// ensureCommandsAreValid(connection);
|
||||
|
||||
QVector<QString> statements;
|
||||
// Reserve * 2 might be enough, can't be predicted :/
|
||||
statements.reserve(m_commands.size() * 2);
|
||||
|
||||
for (const auto &command : std::as_const(m_commands))
|
||||
statements += grammar.invokeCompileMethod(command, connection, *this);
|
||||
|
||||
return statements;
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<> Blueprint::create()
|
||||
{
|
||||
return addCommand(Create);
|
||||
}
|
||||
|
||||
void Blueprint::after(const QString &column,
|
||||
const std::function<void(Blueprint &)> &callback)
|
||||
{
|
||||
m_after = column;
|
||||
|
||||
std::invoke(callback, *this);
|
||||
|
||||
m_after.clear();
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<> Blueprint::drop()
|
||||
{
|
||||
return addCommand(Drop);
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<> Blueprint::dropIfExists()
|
||||
{
|
||||
return addCommand(DropIfExists);
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<> Blueprint::dropColumns(const QVector<QString> &columns)
|
||||
{
|
||||
return addCommand(DropColumn,
|
||||
{.columns = QVector<Column>(columns.cbegin(), columns.cend())});
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<> Blueprint::dropColumn(const QString &column)
|
||||
{
|
||||
return addCommand(DropColumn, {.columns = {column}});
|
||||
}
|
||||
|
||||
void Blueprint::dropTimestamps()
|
||||
{
|
||||
dropColumns({CREATED_AT, UPDATED_AT});
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<> Blueprint::rename(const QString &to)
|
||||
{
|
||||
return addCommand(Rename, {.to = to});
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<>
|
||||
Blueprint::renameColumn(const QString &from, const QString &to)
|
||||
{
|
||||
return addCommand(RenameColumn, {.from_ = from, .to = to});
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<>
|
||||
Blueprint::primary(const QVector<QString> &columns, const QString &name,
|
||||
const QString &algorithm)
|
||||
{
|
||||
return indexCommand(Primary, columns, name, algorithm);
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<>
|
||||
Blueprint::unique(const QVector<QString> &columns, const QString &name,
|
||||
const QString &algorithm)
|
||||
{
|
||||
return indexCommand(Unique, columns, name, algorithm);
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<>
|
||||
Blueprint::index(const QVector<QString> &columns, const QString &name,
|
||||
const QString &algorithm)
|
||||
{
|
||||
return indexCommand(Index, columns, name, algorithm); // NOLINT(readability-suspicious-call-argument)
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<>
|
||||
Blueprint::fullText(const QVector<QString> &columns, const QString &name,
|
||||
const QString &algorithm)
|
||||
{
|
||||
return indexCommand(Fulltext, columns, name, algorithm);
|
||||
}
|
||||
|
||||
// CUR schema, it looks like spatial index can not be created on multiple columns on mysql, if its true remove QVector overloads, error 1070 Too many key parts specified; max 1 parts allowed silverqx
|
||||
ColumnDefinitionReference<>
|
||||
Blueprint::spatialIndex(const QVector<QString> &columns, const QString &name)
|
||||
{
|
||||
return indexCommand(SpatialIndex, columns, name);
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<>
|
||||
Blueprint::rawIndex(const Expression &expression, const QString &name)
|
||||
{
|
||||
return addCommand(Index, {.index = name, .columns = {expression}});
|
||||
}
|
||||
|
||||
ForeignKeyDefinitionReference
|
||||
Blueprint::foreign(const QVector<QString> &columns, const QString &name)
|
||||
{
|
||||
return indexCommand(Foreign, columns, name);
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<> Blueprint::dropPrimary(const QVector<QString> &columns)
|
||||
{
|
||||
return dropIndexCommand(DropPrimary, Primary, columns);
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<> Blueprint::dropUnique(const QVector<QString> &columns)
|
||||
{
|
||||
return dropIndexCommand(DropUnique, Unique, columns);
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<> Blueprint::dropIndex(const QVector<QString> &columns)
|
||||
{
|
||||
return dropIndexCommand(DropIndex, Index, columns);
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<> Blueprint::dropFullText(const QVector<QString> &columns)
|
||||
{
|
||||
return dropIndexCommand(DropFullText, Fulltext, columns);
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<> Blueprint::dropSpatialIndex(const QVector<QString> &columns)
|
||||
{
|
||||
return dropIndexCommand(DropSpatialIndex, SpatialIndex, columns);
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<> Blueprint::dropForeign(const QVector<QString> &columns)
|
||||
{
|
||||
return dropIndexCommand(DropForeign, Foreign, columns);
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<> Blueprint::dropConstrainedForeignId(const QString &column)
|
||||
{
|
||||
dropForeign(QVector<QString> {column});
|
||||
|
||||
return dropColumn(column);
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<> Blueprint::renameIndex(const QString &from, const QString &to)
|
||||
{
|
||||
return addCommand(RenameIndex, {.from_ = from, .to = to});
|
||||
}
|
||||
|
||||
ForeignIdColumnDefinitionReference Blueprint::foreignId(const QString &column)
|
||||
{
|
||||
return {*this, unsignedBigInteger(column)};
|
||||
}
|
||||
|
||||
ForeignIdColumnDefinitionReference Blueprint::foreignUuid(const QString &column)
|
||||
{
|
||||
return {*this, uuid(column)};
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<>
|
||||
Blueprint::integer(const QString &column, const bool autoIncrement,
|
||||
const bool isUnsigned)
|
||||
{
|
||||
return addColumn(ColumnType::Integer, column, {.autoIncrement = autoIncrement,
|
||||
.isUnsigned = isUnsigned});
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<>
|
||||
Blueprint::tinyInteger(const QString &column, const bool autoIncrement,
|
||||
const bool isUnsigned)
|
||||
{
|
||||
return addColumn(ColumnType::TinyInteger, column, {.autoIncrement = autoIncrement,
|
||||
.isUnsigned = isUnsigned});
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<>
|
||||
Blueprint::smallInteger(const QString &column, const bool autoIncrement,
|
||||
const bool isUnsigned)
|
||||
{
|
||||
return addColumn(ColumnType::SmallInteger, column, {.autoIncrement = autoIncrement,
|
||||
.isUnsigned = isUnsigned});
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<>
|
||||
Blueprint::mediumInteger(const QString &column, const bool autoIncrement,
|
||||
const bool isUnsigned)
|
||||
{
|
||||
return addColumn(ColumnType::MediumInteger, column, {.autoIncrement = autoIncrement,
|
||||
.isUnsigned = isUnsigned});
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<>
|
||||
Blueprint::bigInteger(const QString &column, const bool autoIncrement,
|
||||
const bool isUnsigned)
|
||||
{
|
||||
return addColumn(ColumnType::BigInteger, column, {.autoIncrement = autoIncrement,
|
||||
.isUnsigned = isUnsigned});
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<> Blueprint::Char(const QString &column, const int length)
|
||||
{
|
||||
return addColumn(ColumnType::Char, column, {.length = length});
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<> Blueprint::string(const QString &column, const int length)
|
||||
{
|
||||
return addColumn(ColumnType::String, column, {.length = length});
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<> Blueprint::tinyText(const QString &column)
|
||||
{
|
||||
return addColumn(ColumnType::TinyText, column);
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<> Blueprint::text(const QString &column)
|
||||
{
|
||||
return addColumn(ColumnType::Text, column);
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<> Blueprint::mediumText(const QString &column)
|
||||
{
|
||||
return addColumn(ColumnType::MediumText, column);
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<> Blueprint::longText(const QString &column)
|
||||
{
|
||||
return addColumn(ColumnType::LongText, column);
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<>
|
||||
Blueprint::Float(const QString &column, const std::optional<int> total,
|
||||
const std::optional<int> places, const bool isUnsigned)
|
||||
{
|
||||
return addColumn(ColumnType::Float, column, {.places = places, .total = total,
|
||||
.isUnsigned = isUnsigned});
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<>
|
||||
Blueprint::Double(const QString &column, const std::optional<int> total,
|
||||
const std::optional<int> places, const bool isUnsigned)
|
||||
{
|
||||
return addColumn(ColumnType::Double, column, {.places = places, .total = total,
|
||||
.isUnsigned = isUnsigned});
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<>
|
||||
Blueprint::decimal(const QString &column, const std::optional<int> total,
|
||||
const std::optional<int> places, const bool isUnsigned)
|
||||
{
|
||||
return addColumn(ColumnType::Decimal, column, {.places = places, .total = total,
|
||||
.isUnsigned = isUnsigned});
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<> Blueprint::boolean(const QString &column)
|
||||
{
|
||||
return addColumn(ColumnType::Boolean, column);
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<>
|
||||
Blueprint::Enum(const QString &column, const QVector<QString> &allowed)
|
||||
{
|
||||
return addColumn(ColumnType::Enum, column, {.allowed = allowed});
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<>
|
||||
Blueprint::set(const QString &column, const QVector<QString> &allowed)
|
||||
{
|
||||
return addColumn(ColumnType::Set, column, {.allowed = allowed});
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<> Blueprint::json(const QString &column)
|
||||
{
|
||||
return addColumn(ColumnType::Json, column);
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<> Blueprint::jsonb(const QString &column)
|
||||
{
|
||||
return addColumn(ColumnType::Jsonb, column);
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<> Blueprint::date(const QString &column)
|
||||
{
|
||||
return addColumn(ColumnType::Date, column);
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<>
|
||||
Blueprint::dateTime(const QString &column, const int precision)
|
||||
{
|
||||
return addColumn(ColumnType::DateTime, column, {.precision = precision});
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<>
|
||||
Blueprint::dateTimeTz(const QString &column, const int precision)
|
||||
{
|
||||
return addColumn(ColumnType::DateTimeTz, column, {.precision = precision});
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<> Blueprint::time(const QString &column, const int precision)
|
||||
{
|
||||
return addColumn(ColumnType::Time, column, {.precision = precision});
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<> Blueprint::timeTz(const QString &column, const int precision)
|
||||
{
|
||||
return addColumn(ColumnType::TimeTz, column, {.precision = precision});
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<>
|
||||
Blueprint::timestamp(const QString &column, const int precision)
|
||||
{
|
||||
return addColumn(ColumnType::Timestamp, column, {.precision = precision});
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<>
|
||||
Blueprint::timestampTz(const QString &column, const int precision)
|
||||
{
|
||||
return addColumn(ColumnType::TimestampTz, column, {.precision = precision});
|
||||
}
|
||||
|
||||
void Blueprint::timestamps(const int precision)
|
||||
{
|
||||
timestamp(CREATED_AT, precision).nullable();
|
||||
|
||||
timestamp(UPDATED_AT, precision).nullable();
|
||||
}
|
||||
|
||||
void Blueprint::timestampsTz(const int precision)
|
||||
{
|
||||
timestampTz(CREATED_AT, precision).nullable();
|
||||
|
||||
timestampTz(UPDATED_AT, precision).nullable();
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<> Blueprint::year(const QString &column)
|
||||
{
|
||||
return addColumn(ColumnType::Year, column);
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<> Blueprint::binary(const QString &column)
|
||||
{
|
||||
return addColumn(ColumnType::Binary, column);
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<> Blueprint::uuid(const QString &column)
|
||||
{
|
||||
return addColumn(ColumnType::Uuid, column);
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<> Blueprint::ipAddress(const QString &column)
|
||||
{
|
||||
return addColumn(ColumnType::IpAddress, column);
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<> Blueprint::macAddress(const QString &column)
|
||||
{
|
||||
return addColumn(ColumnType::MacAddress, column);
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<> Blueprint::geometry(const QString &column)
|
||||
{
|
||||
return addColumn(ColumnType::Geometry, column);
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<>
|
||||
Blueprint::point(const QString &column, const std::optional<quint32> srid)
|
||||
{
|
||||
return addColumn(ColumnType::Point, column, {.srid = srid});
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<> Blueprint::lineString(const QString &column)
|
||||
{
|
||||
return addColumn(ColumnType::LineString, column);
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<> Blueprint::polygon(const QString &column)
|
||||
{
|
||||
return addColumn(ColumnType::Polygon, column);
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<> Blueprint::geometryCollection(const QString &column)
|
||||
{
|
||||
return addColumn(ColumnType::GeometryCollection, column);
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<> Blueprint::multiPoint(const QString &column)
|
||||
{
|
||||
return addColumn(ColumnType::MultiPoint, column);
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<> Blueprint::multiLineString(const QString &column)
|
||||
{
|
||||
return addColumn(ColumnType::MultiLineString, column);
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<> Blueprint::multiPolygon(const QString &column)
|
||||
{
|
||||
return addColumn(ColumnType::MultiPolygon, column);
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<> Blueprint::multiPolygonZ(const QString &column)
|
||||
{
|
||||
return addColumn(ColumnType::MultiPolygonZ, column);
|
||||
}
|
||||
|
||||
// CUR schema, test computed column silverqx
|
||||
ColumnDefinitionReference<>
|
||||
Blueprint::computed(const QString &column, const QString &expression)
|
||||
{
|
||||
return addColumn(ColumnType::Computed, column, {.expression = expression});
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<> Blueprint::rememberToken()
|
||||
{
|
||||
return string(QStringLiteral("remember_token"), 100).nullable();
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<>
|
||||
Blueprint::addColumn(const ColumnType type, const QString &name,
|
||||
ColumnDefinition &¶meters)
|
||||
{
|
||||
// To be more clear
|
||||
auto &columnDefinition = parameters;
|
||||
|
||||
columnDefinition.type = type;
|
||||
columnDefinition.name = name;
|
||||
|
||||
return addColumnDefinition(std::move(columnDefinition));
|
||||
}
|
||||
|
||||
QVector<ColumnDefinition> Blueprint::getAddedColumns() const
|
||||
{
|
||||
QVector<ColumnDefinition> added;
|
||||
added.reserve(m_columns.size());
|
||||
|
||||
std::ranges::copy_if(m_columns, std::back_inserter(added),
|
||||
[](const auto &column)
|
||||
{
|
||||
return !column.change;
|
||||
});
|
||||
|
||||
return added;
|
||||
}
|
||||
|
||||
QVector<ColumnDefinition> Blueprint::getChangedColumns() const
|
||||
{
|
||||
QVector<ColumnDefinition> added;
|
||||
added.reserve(m_columns.size());
|
||||
|
||||
std::ranges::copy_if(m_columns, std::back_inserter(added),
|
||||
[](const auto &column)
|
||||
{
|
||||
return column.change;
|
||||
});
|
||||
|
||||
return added;
|
||||
}
|
||||
|
||||
bool Blueprint::hasAutoIncrementColumn() const
|
||||
{
|
||||
return ranges::contains(getAddedColumns(), true,
|
||||
[](const ColumnDefinition &column)
|
||||
{
|
||||
return column.autoIncrement;
|
||||
});
|
||||
}
|
||||
|
||||
QVector<AutoIncrementColumnValue> Blueprint::autoIncrementStartingValues() const
|
||||
{
|
||||
if (!hasAutoIncrementColumn())
|
||||
return {};
|
||||
|
||||
auto addedColumns = getAddedColumns();
|
||||
|
||||
// CUR1 ranges, check all pred and proj, now I understand where I have to use auto & or auto &&, note in bash_or_cmd c++ sheet silverqx
|
||||
return addedColumns
|
||||
| ranges::views::filter([](const auto addedColumn)
|
||||
{
|
||||
return addedColumn.autoIncrement;
|
||||
})
|
||||
| ranges::views::transform([](auto &addedColumn)
|
||||
-> AutoIncrementColumnValue
|
||||
{
|
||||
/* When value was not defined then init. it to std::nullopt and filter out
|
||||
in the next operator| chain. */
|
||||
return {std::move(addedColumn.name),
|
||||
addedColumn.startingValue ? *addedColumn.startingValue
|
||||
/* Default value if a startingValue was not
|
||||
defined, can also be the std::nullopt. */
|
||||
: addedColumn.from};
|
||||
})
|
||||
// Filter out items with std::nullopt values to avoid alter table autoIncrement 0
|
||||
| ranges::views::filter([](auto &&autoIncrementColumnValue)
|
||||
{
|
||||
return autoIncrementColumnValue.value;
|
||||
})
|
||||
| ranges::to<QVector<AutoIncrementColumnValue>>();
|
||||
}
|
||||
|
||||
bool Blueprint::creating() const
|
||||
{
|
||||
return ranges::contains(m_commands, Create, [](const auto &command)
|
||||
{
|
||||
return command.name;
|
||||
});
|
||||
}
|
||||
|
||||
Blueprint &Blueprint::removeColumn(const QString &name)
|
||||
{
|
||||
m_columns |= ranges::actions::remove_if([&name](const auto &column)
|
||||
{
|
||||
return column.name == name;
|
||||
});
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Blueprint::defaultStringLength(const int length) noexcept
|
||||
{
|
||||
DefaultStringLength = length;
|
||||
}
|
||||
|
||||
/* protected */
|
||||
|
||||
ColumnDefinitionReference<> Blueprint::addColumnDefinition(ColumnDefinition &&definition)
|
||||
{
|
||||
m_columns.append(std::move(definition));
|
||||
|
||||
auto &definitionRef = m_columns.last(); // clazy:exclude=detaching-member
|
||||
|
||||
if (!m_after.isEmpty()) {
|
||||
definitionRef.after.swap(m_after);
|
||||
|
||||
m_after = definitionRef.name;
|
||||
}
|
||||
|
||||
return definitionRef;
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<>
|
||||
Blueprint::addCommand(const QString &name, ColumnDefinition &¶meters)
|
||||
{
|
||||
auto command = createCommand(name, std::move(parameters));
|
||||
|
||||
m_commands.append(std::move(command));
|
||||
|
||||
return m_commands.last(); // clazy:exclude=detaching-member
|
||||
}
|
||||
|
||||
ColumnDefinition
|
||||
Blueprint::createCommand(const QString &name, ColumnDefinition &¶meters)
|
||||
{
|
||||
// To be more clear
|
||||
auto &commandDefinition = parameters;
|
||||
|
||||
commandDefinition.name = name;
|
||||
|
||||
// CUR schema, move on reference to rvalue param. silverqx
|
||||
return std::move(commandDefinition);
|
||||
}
|
||||
|
||||
void Blueprint::addImpliedCommands(const SchemaGrammar &/*unused*/)
|
||||
{
|
||||
if (!getAddedColumns().isEmpty() && !creating())
|
||||
m_commands.prepend(createCommand(Add));
|
||||
|
||||
// if (!getChangedColumns().isEmpty() && !creating())
|
||||
// m_commands.prepend(createCommand(Change));
|
||||
|
||||
addFluentIndexes();
|
||||
|
||||
// addFluentCommands(grammar);
|
||||
}
|
||||
|
||||
void Blueprint::addFluentIndexes()
|
||||
{
|
||||
/*! Index item for fluent indexes. */
|
||||
struct FluentIndexItem
|
||||
{
|
||||
/*! Index name for the database. */
|
||||
std::reference_wrapper<std::variant<std::monostate, QString, bool>> name;
|
||||
/*! Index type in the string format. */
|
||||
QString type;
|
||||
};
|
||||
|
||||
for (auto &column : m_columns)
|
||||
/* Loop over all column's index data members to check if any index has been
|
||||
defined. */
|
||||
for (std::array indexes {
|
||||
std::to_array<FluentIndexItem>({
|
||||
{std::ref(column.index_), Index},
|
||||
{std::ref(column.primary), Primary},
|
||||
{std::ref(column.fulltext), Fulltext},
|
||||
{std::ref(column.spatialIndex), SpatialIndex},
|
||||
{std::ref(column.unique), Unique}
|
||||
})
|
||||
};
|
||||
auto &&indexItem : indexes
|
||||
) {
|
||||
auto &index = indexItem.name.get();
|
||||
|
||||
if (std::holds_alternative<std::monostate>(index))
|
||||
continue;
|
||||
|
||||
/* If the index has been specified on the given column, but is simply equal
|
||||
to "true" (boolean), no name has been specified for this index so the
|
||||
index method can be called without a name and it will generate one. */
|
||||
if (std::holds_alternative<bool>(index) && std::get<bool>(index)) {
|
||||
indexCommand(indexItem.type, {column.name}, "");
|
||||
|
||||
index = false;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
/* If the index has been specified on the given column, and it has a string
|
||||
value, we'll go ahead and call the index method and pass the name for
|
||||
the index since the developer specified the explicit name for this. */
|
||||
else if(const auto indexName = std::get<QString>(index); // NOLINT(readability-else-after-return)
|
||||
std::holds_alternative<QString>(index) &&
|
||||
!indexName.isEmpty()
|
||||
) {
|
||||
indexCommand(indexItem.type, {column.name}, indexName);
|
||||
|
||||
index = false;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<>
|
||||
Blueprint::indexCommand(const QString &type, const QVector<QString> &columns,
|
||||
const QString &indexName, const QString &algorithm)
|
||||
{
|
||||
/* If no name was specified for this index, we will create one using a basic
|
||||
convention of the table name, followed by the columns, followed by an
|
||||
index type, such as primary or index, which makes the index unique,
|
||||
eg. posts_user_id_foreign or users_name_unique. */
|
||||
return addCommand(type, {.index = indexName.isEmpty() ? createIndexName(type, columns)
|
||||
: indexName,
|
||||
.columns = QVector<Column>(columns.cbegin(), columns.cend()),
|
||||
.algorithm = algorithm});
|
||||
}
|
||||
|
||||
ColumnDefinitionReference<>
|
||||
Blueprint::dropIndexCommand(const QString &command, const QString &type,
|
||||
const QVector<QString> &columns)
|
||||
{
|
||||
// Used by dropPrimary("")
|
||||
if (columns.isEmpty())
|
||||
return indexCommand(command, {}, {});
|
||||
|
||||
/* If the given "index" is actually the vector of columns, the developer means
|
||||
to drop an index merely by specifying the columns involved without the
|
||||
conventional name, so we will build the index name from the columns. */
|
||||
return dropIndexCommand(command, createIndexName(type, columns));
|
||||
}
|
||||
|
||||
// NOTE api different, Eloquent doesn't have overload like this silverqx
|
||||
ColumnDefinitionReference<>
|
||||
Blueprint::dropIndexCommand(const QString &command, const QString &index)
|
||||
{
|
||||
return indexCommand(command, {}, index);
|
||||
}
|
||||
|
||||
QString
|
||||
Blueprint::createIndexName(const QString &type, const QVector<QString> &columns) const
|
||||
{
|
||||
auto index = QStringLiteral("%1_%2_%3")
|
||||
.arg(NOSPACE.arg(m_prefix, m_table),
|
||||
Utils::Container::join(columns, UNDERSCORE),
|
||||
type)
|
||||
.toLower();
|
||||
|
||||
return index.replace(DASH, UNDERSCORE).replace(DOT, UNDERSCORE);
|
||||
}
|
||||
|
||||
} // namespace Orm::SchemaNs
|
||||
|
||||
TINYORM_END_COMMON_NAMESPACE
|
||||
43
src/orm/schema/foreignidcolumndefinitionreference.cpp
Normal file
43
src/orm/schema/foreignidcolumndefinitionreference.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
#include "orm/schema/foreignidcolumndefinitionreference.hpp"
|
||||
|
||||
#include "orm/schema/blueprint.hpp"
|
||||
|
||||
TINYORM_BEGIN_COMMON_NAMESPACE
|
||||
|
||||
namespace Orm::SchemaNs
|
||||
{
|
||||
|
||||
ForeignIdColumnDefinitionReference::ForeignIdColumnDefinitionReference(
|
||||
Blueprint &blueprint,
|
||||
const ColumnDefinitionReference<> columnDefinitionReference
|
||||
)
|
||||
: ColumnDefinitionReference(columnDefinitionReference.m_columnDefinition)
|
||||
, m_blueprint(blueprint)
|
||||
, m_columnDefinition(columnDefinitionReference.m_columnDefinition)
|
||||
{}
|
||||
|
||||
ForeignKeyDefinitionReference
|
||||
ForeignIdColumnDefinitionReference::constrained(const QString &table,
|
||||
const QString &column)
|
||||
{
|
||||
// Guess table name, cut off _column from the foreign index name and make it plural
|
||||
const auto &foreignName = m_columnDefinition.get().name;
|
||||
|
||||
const auto guessTable = QStringLiteral("%1s")
|
||||
.arg(foreignName.left(
|
||||
foreignName.lastIndexOf(
|
||||
QStringLiteral("_%1").arg(column))));
|
||||
|
||||
return references(QVector<QString> {column})
|
||||
.on(table.isEmpty() ? guessTable : table);
|
||||
}
|
||||
|
||||
ForeignKeyDefinitionReference
|
||||
ForeignIdColumnDefinitionReference::references(const QVector<QString> &columns)
|
||||
{
|
||||
return m_blueprint.foreign(m_columnDefinition.get().name).references(columns);
|
||||
}
|
||||
|
||||
} // namespace Orm::SchemaNs
|
||||
|
||||
TINYORM_END_COMMON_NAMESPACE
|
||||
82
src/orm/schema/foreignkeydefinitionreference.cpp
Normal file
82
src/orm/schema/foreignkeydefinitionreference.cpp
Normal file
@@ -0,0 +1,82 @@
|
||||
#include "orm/schema/foreignkeydefinitionreference.hpp"
|
||||
|
||||
#include "orm/schema/foreignidcolumndefinitionreference.hpp"
|
||||
#include "orm/schema/schemaconstants.hpp"
|
||||
|
||||
TINYORM_BEGIN_COMMON_NAMESPACE
|
||||
|
||||
namespace Orm::SchemaNs
|
||||
{
|
||||
|
||||
ForeignKeyDefinitionReference::ForeignKeyDefinitionReference(
|
||||
const ColumnDefinitionReference<> columnDefinitionReference
|
||||
)
|
||||
: m_columnDefinition(columnDefinitionReference.m_columnDefinition)
|
||||
{}
|
||||
|
||||
ForeignKeyDefinitionReference::ForeignKeyDefinitionReference(
|
||||
ForeignIdColumnDefinitionReference foreignIdColumnReference
|
||||
)
|
||||
: m_columnDefinition(foreignIdColumnReference.m_columnDefinition)
|
||||
{}
|
||||
|
||||
ForeignKeyDefinitionReference &
|
||||
ForeignKeyDefinitionReference::references(const QVector<QString> &columns)
|
||||
{
|
||||
m_columnDefinition.get().references = columns;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
ForeignKeyDefinitionReference &
|
||||
ForeignKeyDefinitionReference::on(const QString &table)
|
||||
{
|
||||
m_columnDefinition.get().on = table;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
ForeignKeyDefinitionReference &
|
||||
ForeignKeyDefinitionReference::onDelete(const QString &action)
|
||||
{
|
||||
m_columnDefinition.get().onDelete = action;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
ForeignKeyDefinitionReference &
|
||||
ForeignKeyDefinitionReference::onUpdate(const QString &action)
|
||||
{
|
||||
m_columnDefinition.get().onUpdate = action;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
ForeignKeyDefinitionReference &ForeignKeyDefinitionReference::cascadeOnUpdate()
|
||||
{
|
||||
return onUpdate(Cascade);
|
||||
}
|
||||
|
||||
ForeignKeyDefinitionReference &ForeignKeyDefinitionReference::restrictOnUpdate()
|
||||
{
|
||||
return onUpdate(Restrict);
|
||||
}
|
||||
|
||||
ForeignKeyDefinitionReference &ForeignKeyDefinitionReference::cascadeOnDelete()
|
||||
{
|
||||
return onDelete(Cascade);
|
||||
}
|
||||
|
||||
ForeignKeyDefinitionReference &ForeignKeyDefinitionReference::restrictOnDelete()
|
||||
{
|
||||
return onDelete(Restrict);
|
||||
}
|
||||
|
||||
ForeignKeyDefinitionReference &ForeignKeyDefinitionReference::nullOnDelete()
|
||||
{
|
||||
return onDelete(SetNull);
|
||||
}
|
||||
|
||||
} // namespace Orm::SchemaNs
|
||||
|
||||
TINYORM_END_COMMON_NAMESPACE
|
||||
@@ -1,10 +1,77 @@
|
||||
#include "orm/schema/grammars/mysqlschemagrammar.hpp"
|
||||
|
||||
#include <unordered_set>
|
||||
|
||||
#include "orm/databaseconnection.hpp"
|
||||
#include "orm/macros/threadlocal.hpp"
|
||||
#include "orm/utils/type.hpp"
|
||||
|
||||
TINYORM_BEGIN_COMMON_NAMESPACE
|
||||
|
||||
namespace Orm::Schema::Grammars
|
||||
using Orm::Constants::charset_;
|
||||
using Orm::Constants::collation_;
|
||||
using Orm::Constants::engine_;
|
||||
|
||||
namespace Orm::SchemaNs::Grammars
|
||||
{
|
||||
|
||||
/* Compile methods for the SchemaBuilder */
|
||||
|
||||
/* public */
|
||||
|
||||
QString MySqlSchemaGrammar::compileCreateDatabase(
|
||||
const QString &name, DatabaseConnection &connection) const
|
||||
{
|
||||
return QStringLiteral("create database %1 "
|
||||
"default character set %2 default collate %3")
|
||||
.arg(wrapValue(name),
|
||||
wrapValue(connection.getConfig(charset_).value<QString>()),
|
||||
wrapValue(connection.getConfig(collation_).value<QString>()));
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::compileDropDatabaseIfExists(const QString &name) const
|
||||
{
|
||||
return QStringLiteral("drop database if exists %1").arg(wrapValue(name));
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::compileDropAllTables(const QVector<QString> &tables) const
|
||||
{
|
||||
return QStringLiteral("drop table %1").arg(columnize(tables));
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::compileDropAllViews(const QVector<QString> &views) const
|
||||
{
|
||||
return QStringLiteral("drop view %1").arg(columnize(views));
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::compileGetAllTables() const
|
||||
{
|
||||
return QStringLiteral("SHOW FULL TABLES WHERE table_type = 'BASE TABLE';");
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::compileGetAllViews() const
|
||||
{
|
||||
return QStringLiteral("SHOW FULL TABLES WHERE table_type = 'VIEW';");
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::compileEnableForeignKeyConstraints() const
|
||||
{
|
||||
return QStringLiteral("SET FOREIGN_KEY_CHECKS=1;");
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::compileDisableForeignKeyConstraints() const
|
||||
{
|
||||
return QStringLiteral("SET FOREIGN_KEY_CHECKS=0;");
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::compileTableExists() const
|
||||
{
|
||||
return QStringLiteral("select * "
|
||||
"from `information_schema`.`tables` "
|
||||
"where `table_schema` = ? and `table_name` = ? and "
|
||||
"`table_type` = 'BASE TABLE'");
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::compileColumnListing(const QString &/*unused*/) const
|
||||
{
|
||||
return QStringLiteral("select `column_name` as `column_name` "
|
||||
@@ -12,6 +79,854 @@ QString MySqlSchemaGrammar::compileColumnListing(const QString &/*unused*/) cons
|
||||
"where `table_schema` = ? and `table_name` = ?");
|
||||
}
|
||||
|
||||
} // namespace Orm::Schema::Grammars
|
||||
/* Compile methods for commands */
|
||||
|
||||
/* public */
|
||||
|
||||
QVector<QString>
|
||||
MySqlSchemaGrammar::compileCreate(
|
||||
const Blueprint &blueprint, const ColumnDefinition &command,
|
||||
const DatabaseConnection &connection) const
|
||||
{
|
||||
// Primary SQL query for create table
|
||||
auto sqlCreateTable = compileCreateTable(blueprint, command, connection);
|
||||
|
||||
// Add the encoding option to the SQL for the table
|
||||
compileCreateEncoding(sqlCreateTable, connection, blueprint);
|
||||
|
||||
// Add storage engine declaration to the SQL query if has been supplied
|
||||
compileCreateEngine(sqlCreateTable, connection, blueprint);
|
||||
|
||||
// Add autoIncrement starting values to the SQL query if have been supplied
|
||||
auto autoIncrementStartingValues = compileAutoIncrementStartingValues(blueprint);
|
||||
|
||||
/* Prepare container with all sql queries, autoIncrement for every column uses
|
||||
alter table, so separate SQL queries are provided for every column. */
|
||||
QVector<QString> sql {sqlCreateTable};
|
||||
if (!autoIncrementStartingValues.isEmpty())
|
||||
sql << std::move(autoIncrementStartingValues);
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
QVector<QString> MySqlSchemaGrammar::compileDrop(
|
||||
const Blueprint &blueprint, const ColumnDefinition &/*unused*/) const
|
||||
{
|
||||
return {QStringLiteral("drop table %1").arg(wrapTable(blueprint))};
|
||||
}
|
||||
|
||||
QVector<QString> MySqlSchemaGrammar::compileDropIfExists(
|
||||
const Blueprint &blueprint, const ColumnDefinition &/*unused*/) const
|
||||
{
|
||||
return {QStringLiteral("drop table if exists %1").arg(wrapTable(blueprint))};
|
||||
}
|
||||
|
||||
QVector<QString> MySqlSchemaGrammar::compileRename(
|
||||
const Blueprint &blueprint, const ColumnDefinition &command) const
|
||||
{
|
||||
return {QStringLiteral("rename table %1 to %2")
|
||||
.arg(wrapTable(blueprint), BaseGrammar::wrap(command.to))};
|
||||
}
|
||||
|
||||
QVector<QString> MySqlSchemaGrammar::compileAdd(const Blueprint &blueprint,
|
||||
const ColumnDefinition &/*unused*/) const
|
||||
{
|
||||
auto columns = prefixArray(Add, getColumns(blueprint));
|
||||
|
||||
// Add autoIncrement starting values to the SQL query if have been supplied
|
||||
auto autoIncrementStartingValues = compileAutoIncrementStartingValues(blueprint);
|
||||
|
||||
auto sqlAlterTable = QStringLiteral("alter table %1 %2")
|
||||
.arg(wrapTable(blueprint), columnizeWithoutWrap(columns));
|
||||
|
||||
/* Prepare container with all sql queries, autoIncrement for every column uses
|
||||
alter table, so separate SQL queries are provided for every column. */
|
||||
QVector<QString> sql {sqlAlterTable};
|
||||
if (!autoIncrementStartingValues.isEmpty())
|
||||
sql << std::move(autoIncrementStartingValues);
|
||||
|
||||
return sql;
|
||||
}
|
||||
|
||||
QVector<QString> MySqlSchemaGrammar::compileDropColumn(
|
||||
const Blueprint &blueprint, const ColumnDefinition &command) const
|
||||
{
|
||||
return {QStringLiteral("alter table %1 %2")
|
||||
.arg(wrapTable(blueprint),
|
||||
columnizeWithoutWrap(prefixArray(Drop,
|
||||
wrapArray(command.columns))))};
|
||||
}
|
||||
|
||||
QVector<QString> MySqlSchemaGrammar::compileRenameColumn(
|
||||
const Blueprint &blueprint, const ColumnDefinition &command) const
|
||||
{
|
||||
return {QStringLiteral("alter table %1 rename column %2 to %3")
|
||||
.arg(wrapTable(blueprint), BaseGrammar::wrap(command.from_),
|
||||
BaseGrammar::wrap(command.to))};
|
||||
}
|
||||
|
||||
QVector<QString> MySqlSchemaGrammar::compilePrimary(
|
||||
const Blueprint &blueprint, const ColumnDefinition &command) const
|
||||
{
|
||||
// CUR schema, check this, why it is doing, I have to make command non-const silverqx
|
||||
// command.name.clear();
|
||||
|
||||
return {compileKey(blueprint, command, QStringLiteral("primary key"))};
|
||||
}
|
||||
|
||||
QVector<QString> MySqlSchemaGrammar::compileUnique(
|
||||
const Blueprint &blueprint, const ColumnDefinition &command) const
|
||||
{
|
||||
return {compileKey(blueprint, command, Unique)};
|
||||
}
|
||||
|
||||
QVector<QString> MySqlSchemaGrammar::compileIndex(
|
||||
const Blueprint &blueprint, const ColumnDefinition &command) const
|
||||
{
|
||||
return {compileKey(blueprint, command, Index)};
|
||||
}
|
||||
|
||||
QVector<QString> MySqlSchemaGrammar::compileFullText(
|
||||
const Blueprint &blueprint, const ColumnDefinition &command) const
|
||||
{
|
||||
return {compileKey(blueprint, command, Fulltext)};
|
||||
}
|
||||
|
||||
QVector<QString> MySqlSchemaGrammar::compileSpatialIndex(
|
||||
const Blueprint &blueprint, const ColumnDefinition &command) const
|
||||
{
|
||||
return {compileKey(blueprint, command, QStringLiteral("spatial index"))};
|
||||
}
|
||||
|
||||
QVector<QString> MySqlSchemaGrammar::compileDropPrimary(
|
||||
const Blueprint &blueprint, const ColumnDefinition &/*unused*/) const
|
||||
{
|
||||
return {QStringLiteral("alter table %1 drop primary key")
|
||||
.arg(wrapTable(blueprint))};
|
||||
}
|
||||
|
||||
QVector<QString> MySqlSchemaGrammar::compileDropIndex(
|
||||
const Blueprint &blueprint, const ColumnDefinition &command) const
|
||||
{
|
||||
return {QStringLiteral("alter table %1 drop index %2")
|
||||
.arg(wrapTable(blueprint), BaseGrammar::wrap(command.index))};
|
||||
}
|
||||
|
||||
QVector<QString> MySqlSchemaGrammar::compileDropForeign(
|
||||
const Blueprint &blueprint, const ColumnDefinition &command) const
|
||||
{
|
||||
return {QStringLiteral("alter table %1 drop foreign key %2")
|
||||
.arg(wrapTable(blueprint), BaseGrammar::wrap(command.index))};
|
||||
}
|
||||
|
||||
QVector<QString> MySqlSchemaGrammar::compileRenameIndex(
|
||||
const Blueprint &blueprint, const ColumnDefinition &command) const
|
||||
{
|
||||
return {QStringLiteral("alter table %1 rename index %2 to %3")
|
||||
.arg(wrapTable(blueprint), BaseGrammar::wrap(command.from_),
|
||||
BaseGrammar::wrap(command.to))};
|
||||
}
|
||||
|
||||
QVector<QString>
|
||||
MySqlSchemaGrammar::invokeCompileMethod(const ColumnDefinition &command,
|
||||
const DatabaseConnection &connection,
|
||||
const Blueprint &blueprint) const
|
||||
{
|
||||
/*! Type for the compileXx() methods. */
|
||||
using CompileMemFn =
|
||||
std::function<QVector<QString>(
|
||||
const MySqlSchemaGrammar &, const Blueprint &,
|
||||
const ColumnDefinition &)>;
|
||||
|
||||
/* Helps to avoid declare all compileXx() methods with a DatabaseConenction &
|
||||
parameter, only the compileCreate() needs connection argument. */
|
||||
const auto bindCreate = [&connection](auto &&compileMethod)
|
||||
{
|
||||
return [&connection,
|
||||
compileMethod = std::forward<decltype (compileMethod)>(compileMethod)]
|
||||
(const MySqlSchemaGrammar &grammar, const Blueprint &blueprint,
|
||||
const ColumnDefinition &command)
|
||||
{
|
||||
return std::invoke(compileMethod, grammar, blueprint, command, connection);
|
||||
};
|
||||
};
|
||||
|
||||
// CUR schema, use enum, indexCommand() calls createIndexName() that needs also command.name silverqx
|
||||
/* Pointers to a command's compile member methods by a command name, yes yes c++ 😂.
|
||||
I have to map by QString instead of enum struct because a command.name is used
|
||||
to look up, I could use enum struct but I had to map
|
||||
QString(command.name) -> enum. */
|
||||
T_THREAD_LOCAL
|
||||
static const std::unordered_map<QString, CompileMemFn> cached {
|
||||
{Create, bindCreate(&MySqlSchemaGrammar::compileCreate)},
|
||||
|
||||
{Add, &MySqlSchemaGrammar::compileAdd},
|
||||
{Rename, &MySqlSchemaGrammar::compileRename},
|
||||
{Drop, &MySqlSchemaGrammar::compileDrop},
|
||||
{DropIfExists, &MySqlSchemaGrammar::compileDropIfExists},
|
||||
{DropColumn, &MySqlSchemaGrammar::compileDropColumn},
|
||||
{RenameColumn, &MySqlSchemaGrammar::compileRenameColumn},
|
||||
{Primary, &MySqlSchemaGrammar::compilePrimary},
|
||||
{Unique, &MySqlSchemaGrammar::compileUnique},
|
||||
{Index, &MySqlSchemaGrammar::compileIndex},
|
||||
{Fulltext, &MySqlSchemaGrammar::compileFullText},
|
||||
{SpatialIndex, &MySqlSchemaGrammar::compileSpatialIndex},
|
||||
{Foreign, &MySqlSchemaGrammar::compileForeign},
|
||||
{DropPrimary, &MySqlSchemaGrammar::compileDropPrimary},
|
||||
{DropUnique, &MySqlSchemaGrammar::compileDropUnique},
|
||||
{DropIndex, &MySqlSchemaGrammar::compileDropIndex},
|
||||
{DropFullText, &MySqlSchemaGrammar::compileDropFullText},
|
||||
{DropSpatialIndex, &MySqlSchemaGrammar::compileDropSpatialIndex},
|
||||
{DropForeign, &MySqlSchemaGrammar::compileDropForeign},
|
||||
{RenameIndex, &MySqlSchemaGrammar::compileRenameIndex},
|
||||
};
|
||||
|
||||
Q_ASSERT_X(cached.contains(command.name),
|
||||
qUtf8Printable(__tiny_func__),
|
||||
QStringLiteral("Compile methods map doesn't contain the '%1' key.")
|
||||
.arg(command.name)
|
||||
.toUtf8().constData());
|
||||
|
||||
return std::invoke(cached.at(command.name), *this, blueprint, command);
|
||||
}
|
||||
|
||||
/* protected */
|
||||
|
||||
QString
|
||||
MySqlSchemaGrammar::compileCreateTable(
|
||||
const Blueprint &blueprint, const ColumnDefinition &/*unused*/,
|
||||
const DatabaseConnection &/*unused*/) const
|
||||
{
|
||||
return QStringLiteral("%1 table %2 (%3)")
|
||||
.arg(blueprint.isTemporary() ? QStringLiteral("create temporary")
|
||||
: Create,
|
||||
wrapTable(blueprint),
|
||||
columnizeWithoutWrap(getColumns(blueprint)))
|
||||
.trimmed();
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::addModifiers(QString &&sql,
|
||||
const ColumnDefinition &column) const
|
||||
{
|
||||
// CUR schema, should be T_THREAD_LOCAL? silverqx
|
||||
constexpr static std::array modifierMethods {
|
||||
&MySqlSchemaGrammar::modifyUnsigned, &MySqlSchemaGrammar::modifyCharset,
|
||||
&MySqlSchemaGrammar::modifyCollate, &MySqlSchemaGrammar::modifyVirtualAs,
|
||||
&MySqlSchemaGrammar::modifyStoredAs, &MySqlSchemaGrammar::modifyNullable,
|
||||
&MySqlSchemaGrammar::modifyInvisible, &MySqlSchemaGrammar::modifySrid,
|
||||
&MySqlSchemaGrammar::modifyDefault, &MySqlSchemaGrammar::modifyIncrement,
|
||||
&MySqlSchemaGrammar::modifyComment, &MySqlSchemaGrammar::modifyAfter,
|
||||
&MySqlSchemaGrammar::modifyFirst,
|
||||
};
|
||||
|
||||
for (const auto method : modifierMethods)
|
||||
sql.append(std::invoke(method, this, column));
|
||||
|
||||
return std::move(sql);
|
||||
}
|
||||
|
||||
void MySqlSchemaGrammar::compileCreateEncoding(
|
||||
QString &sql, const DatabaseConnection &connection,
|
||||
const Blueprint &blueprint) const
|
||||
{
|
||||
static const auto charsetTmpl = QStringLiteral(" default character set %1");
|
||||
static const auto collateTmpl = QStringLiteral(" collate %1");
|
||||
|
||||
/* First we will set the character set if one has been set on either the create
|
||||
blueprint itself or on the root configuration for the connection that the
|
||||
table is being created on. We will add these to the create table query. */
|
||||
if (!blueprint.charset.isEmpty())
|
||||
sql.append(charsetTmpl.arg(blueprint.charset));
|
||||
|
||||
else if (const auto charset = connection.getConfig(charset_).value<QString>();
|
||||
!charset.isEmpty()
|
||||
)
|
||||
sql.append(charsetTmpl.arg(charset));
|
||||
|
||||
/* Next we will add the collation to the create table statement if one has been
|
||||
added to either this create table blueprint or the configuration for this
|
||||
connection that the query is targeting. We'll add it to this SQL query. */
|
||||
if (!blueprint.collation.isEmpty())
|
||||
sql.append(collateTmpl.arg(quoteString(blueprint.collation)));
|
||||
else if (const auto collation = connection.getConfig(collation_).value<QString>();
|
||||
!collation.isEmpty()
|
||||
)
|
||||
sql.append(collateTmpl.arg(quoteString(collation)));
|
||||
}
|
||||
|
||||
void MySqlSchemaGrammar::compileCreateEngine(
|
||||
QString &sql, const DatabaseConnection &connection,
|
||||
const Blueprint &blueprint) const
|
||||
{
|
||||
static const auto engineTmpl = QStringLiteral(" engine = %1");
|
||||
|
||||
if (!blueprint.engine.isEmpty())
|
||||
sql.append(engineTmpl.arg(blueprint.engine));
|
||||
|
||||
else if (const auto engine = connection.getConfig(engine_).value<QString>();
|
||||
!engine.isEmpty()
|
||||
)
|
||||
sql.append(engineTmpl.arg(engine));
|
||||
}
|
||||
|
||||
QVector<QString>
|
||||
MySqlSchemaGrammar::compileAutoIncrementStartingValues(const Blueprint &blueprint) const
|
||||
{
|
||||
const auto autoIncrementStartingValues = blueprint.autoIncrementStartingValues();
|
||||
|
||||
// Nothing to compile
|
||||
if (autoIncrementStartingValues.isEmpty())
|
||||
return {};
|
||||
|
||||
return autoIncrementStartingValues
|
||||
| ranges::views::transform([this, &blueprint](const auto &startingValue)
|
||||
-> QString
|
||||
{
|
||||
Q_ASSERT(startingValue.value);
|
||||
|
||||
return QStringLiteral("alter table %1 auto_increment = %2")
|
||||
.arg(wrapTable(blueprint))
|
||||
.arg(*startingValue.value);
|
||||
})
|
||||
| ranges::to<QVector<QString>>();
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::compileKey(
|
||||
const Blueprint &blueprint, const ColumnDefinition &command,
|
||||
const QString &type) const
|
||||
{
|
||||
static const auto usingTmpl = QStringLiteral(" using %1");
|
||||
|
||||
return QStringLiteral("alter table %1 add %2 %3%4(%5)")
|
||||
.arg(wrapTable(blueprint), type, BaseGrammar::wrap(command.index),
|
||||
command.algorithm.isEmpty() ? ""
|
||||
: usingTmpl.arg(command.algorithm),
|
||||
columnize(command.columns));
|
||||
}
|
||||
|
||||
// CUR duplicate in MysqlGrammar silverqx
|
||||
QString MySqlSchemaGrammar::wrapValue(QString value) const
|
||||
{
|
||||
if (value == ASTERISK_C)
|
||||
return value;
|
||||
|
||||
return QStringLiteral("`%1`").arg(value.replace(QStringLiteral("`"),
|
||||
QStringLiteral("``")));
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::addSlashes(QString value) const
|
||||
{
|
||||
return value
|
||||
.replace(QChar(0x001a), "^Z")
|
||||
.replace(QChar('\\'), "\\\\")
|
||||
.replace(QChar(QChar::Null), "\\0")
|
||||
.replace(QChar(QChar::LineFeed), "\\n")
|
||||
.replace(QChar(QChar::Tabulation), "\\t")
|
||||
.replace(QChar(0x0008), "\\b")
|
||||
.replace(QChar(0x000d), "\\r")
|
||||
.replace(QChar('"'), "\\\"")
|
||||
.replace(QChar(0x0027), "\\'");
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::getType(const ColumnDefinition &column) const
|
||||
{
|
||||
switch (column.type) {
|
||||
case ColumnType::Char:
|
||||
return typeChar(column);
|
||||
|
||||
case ColumnType::String:
|
||||
return typeString(column);
|
||||
|
||||
case ColumnType::Text:
|
||||
return typeText(column);
|
||||
|
||||
case ColumnType::TinyText:
|
||||
return typeTinyText(column);
|
||||
|
||||
case ColumnType::MediumText:
|
||||
return typeMediumText(column);
|
||||
|
||||
case ColumnType::LongText:
|
||||
return typeLongText(column);
|
||||
|
||||
case ColumnType::Integer:
|
||||
return typeInteger(column);
|
||||
|
||||
case ColumnType::TinyInteger:
|
||||
return typeTinyInteger(column);
|
||||
|
||||
case ColumnType::SmallInteger:
|
||||
return typeSmallInteger(column);
|
||||
|
||||
case ColumnType::MediumInteger:
|
||||
return typeMediumInteger(column);
|
||||
|
||||
case ColumnType::BigInteger:
|
||||
return typeBigInteger(column);
|
||||
|
||||
case ColumnType::Float:
|
||||
return typeFloat(column);
|
||||
|
||||
case ColumnType::Double:
|
||||
return typeDouble(column);
|
||||
|
||||
case ColumnType::Decimal:
|
||||
return typeDecimal(column);
|
||||
|
||||
// PostgreSQL only
|
||||
// case ColumnType::Real:
|
||||
// return typeReal(column);
|
||||
|
||||
case ColumnType::Boolean:
|
||||
return typeBoolean(column);
|
||||
|
||||
case ColumnType::Enum:
|
||||
return typeEnum(column);
|
||||
|
||||
// MySQL only
|
||||
case ColumnType::Set:
|
||||
return typeSet(column);
|
||||
|
||||
case ColumnType::Json:
|
||||
return typeJson(column);
|
||||
|
||||
case ColumnType::Jsonb:
|
||||
return typeJsonb(column);
|
||||
|
||||
case ColumnType::Date:
|
||||
return typeDate(column);
|
||||
|
||||
case ColumnType::DateTime:
|
||||
return typeDateTime(column);
|
||||
|
||||
case ColumnType::DateTimeTz:
|
||||
return typeDateTimeTz(column);
|
||||
|
||||
case ColumnType::Time:
|
||||
return typeTime(column);
|
||||
|
||||
case ColumnType::TimeTz:
|
||||
return typeTimeTz(column);
|
||||
|
||||
case ColumnType::Timestamp:
|
||||
return typeTimestamp(column);
|
||||
|
||||
case ColumnType::TimestampTz:
|
||||
return typeTimestampTz(column);
|
||||
|
||||
case ColumnType::Year:
|
||||
return typeYear(column);
|
||||
|
||||
case ColumnType::Binary:
|
||||
return typeBinary(column);
|
||||
|
||||
case ColumnType::Uuid:
|
||||
return typeUuid(column);
|
||||
|
||||
case ColumnType::IpAddress:
|
||||
return typeIpAddress(column);
|
||||
|
||||
case ColumnType::MacAddress:
|
||||
return typeMacAddress(column);
|
||||
|
||||
case ColumnType::Geometry:
|
||||
return typeGeometry(column);
|
||||
|
||||
case ColumnType::Point:
|
||||
return typePoint(column);
|
||||
|
||||
case ColumnType::LineString:
|
||||
return typeLineString(column);
|
||||
|
||||
case ColumnType::Polygon:
|
||||
return typePolygon(column);
|
||||
|
||||
case ColumnType::GeometryCollection:
|
||||
return typeGeometryCollection(column);
|
||||
|
||||
case ColumnType::MultiPoint:
|
||||
return typeMultiPoint(column);
|
||||
|
||||
case ColumnType::MultiLineString:
|
||||
return typeMultiLineString(column);
|
||||
|
||||
case ColumnType::MultiPolygon:
|
||||
return typeMultiPolygon(column);
|
||||
|
||||
// PostgreSQL only
|
||||
// case ColumnType::MultiPolygonZ:
|
||||
// return typeMultiPolygonZ(column);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
throw Exceptions::RuntimeError(
|
||||
QStringLiteral("Unsupported column type in %1().").arg(__tiny_func__));
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::typeChar(const ColumnDefinition &column) const
|
||||
{
|
||||
return QStringLiteral("char(%1)").arg(column.length);
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::typeString(const ColumnDefinition &column) const
|
||||
{
|
||||
return QStringLiteral("varchar(%1)").arg(column.length);
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::typeTinyText(const ColumnDefinition &/*unused*/) const
|
||||
{
|
||||
return QStringLiteral("tinytext");
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::typeText(const ColumnDefinition &/*unused*/) const
|
||||
{
|
||||
return QStringLiteral("text");
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::typeMediumText(const ColumnDefinition &/*unused*/) const
|
||||
{
|
||||
return QStringLiteral("mediumtext");
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::typeLongText(const ColumnDefinition &/*unused*/) const
|
||||
{
|
||||
return QStringLiteral("longtext");
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::typeBigInteger(const ColumnDefinition &/*unused*/) const
|
||||
{
|
||||
return QStringLiteral("bigint");
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::typeInteger(const ColumnDefinition &/*unused*/) const
|
||||
{
|
||||
return QStringLiteral("int");
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::typeMediumInteger(const ColumnDefinition &/*unused*/) const
|
||||
{
|
||||
return QStringLiteral("mediumint");
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::typeTinyInteger(const ColumnDefinition &/*unused*/) const
|
||||
{
|
||||
return QStringLiteral("tinyint");
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::typeSmallInteger(const ColumnDefinition &/*unused*/) const
|
||||
{
|
||||
return QStringLiteral("smallint");
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::typeFloat(const ColumnDefinition &column) const
|
||||
{
|
||||
return typeDouble(column);
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::typeDouble(const ColumnDefinition &column) const
|
||||
{
|
||||
if (column.total && column.places)
|
||||
return QStringLiteral("double(%1, %2)").arg(*column.total).arg(*column.places);
|
||||
|
||||
return QStringLiteral("double");
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::typeDecimal(const ColumnDefinition &column) const
|
||||
{
|
||||
Q_ASSERT(column.total && column.places);
|
||||
|
||||
return QStringLiteral("decimal(%1, %2)").arg(*column.total).arg(*column.places);
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::typeBoolean(const ColumnDefinition &/*unused*/) const
|
||||
{
|
||||
return QStringLiteral("tinyint(1)");
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::typeEnum(const ColumnDefinition &column) const
|
||||
{
|
||||
return QStringLiteral("enum(%1)").arg(quoteString(column.allowed));
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::typeSet(const ColumnDefinition &column) const
|
||||
{
|
||||
return QStringLiteral("set(%1)").arg(quoteString(column.allowed));
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::typeJson(const ColumnDefinition &/*unused*/) const
|
||||
{
|
||||
return QStringLiteral("json");
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::typeJsonb(const ColumnDefinition &/*unused*/) const
|
||||
{
|
||||
return QStringLiteral("json");
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::typeDate(const ColumnDefinition &/*unused*/) const
|
||||
{
|
||||
return QStringLiteral("date");
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::typeDateTime(const ColumnDefinition &column) const
|
||||
{
|
||||
auto columnType = column.precision > 0
|
||||
? QStringLiteral("datetime(%1)").arg(column.precision)
|
||||
: QStringLiteral("datetime");
|
||||
|
||||
const auto current = column.precision > 0
|
||||
? QStringLiteral("CURRENT_TIMESTAMP(%1)").arg(column.precision)
|
||||
: QStringLiteral("CURRENT_TIMESTAMP");
|
||||
|
||||
columnType = column.useCurrent
|
||||
? QStringLiteral("%1 default %2").arg(columnType, current)
|
||||
: columnType;
|
||||
|
||||
return column.useCurrentOnUpdate
|
||||
? QStringLiteral("%1 on update %2").arg(columnType, current)
|
||||
: columnType;
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::typeDateTimeTz(const ColumnDefinition &column) const
|
||||
{
|
||||
return typeDateTime(column);
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::typeTime(const ColumnDefinition &column) const
|
||||
{
|
||||
return column.precision > 0 ? QStringLiteral("time(%1)").arg(column.precision)
|
||||
: QStringLiteral("time");
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::typeTimeTz(const ColumnDefinition &column) const
|
||||
{
|
||||
return typeTime(column);
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::typeTimestamp(const ColumnDefinition &column) const
|
||||
{
|
||||
auto columnType = column.precision > 0
|
||||
? QStringLiteral("timestamp(%1)").arg(column.precision)
|
||||
: QStringLiteral("timestamp");
|
||||
|
||||
const auto current = column.precision > 0
|
||||
? QStringLiteral("CURRENT_TIMESTAMP(%1)").arg(column.precision)
|
||||
: QStringLiteral("CURRENT_TIMESTAMP");
|
||||
|
||||
columnType = column.useCurrent
|
||||
? QStringLiteral("%1 default %2").arg(columnType, current)
|
||||
: columnType;
|
||||
|
||||
return column.useCurrentOnUpdate
|
||||
? QStringLiteral("%1 on update %2").arg(columnType, current)
|
||||
: columnType;
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::typeTimestampTz(const ColumnDefinition &column) const
|
||||
{
|
||||
return typeTimestamp(column);
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::typeYear(const ColumnDefinition &/*unused*/) const
|
||||
{
|
||||
return QStringLiteral("year");
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::typeBinary(const ColumnDefinition &/*unused*/) const
|
||||
{
|
||||
return QStringLiteral("blob");
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::typeUuid(const ColumnDefinition &/*unused*/) const
|
||||
{
|
||||
return QStringLiteral("char(36)");
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::typeIpAddress(const ColumnDefinition &/*unused*/) const
|
||||
{
|
||||
return QStringLiteral("varchar(45)");
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::typeMacAddress(const ColumnDefinition &/*unused*/) const
|
||||
{
|
||||
return QStringLiteral("varchar(17)");
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::typeGeometry(const ColumnDefinition &/*unused*/) const
|
||||
{
|
||||
return QStringLiteral("geometry");
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::typePoint(const ColumnDefinition &/*unused*/) const
|
||||
{
|
||||
return QStringLiteral("point");
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::typeLineString(const ColumnDefinition &/*unused*/) const
|
||||
{
|
||||
return QStringLiteral("linestring");
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::typePolygon(const ColumnDefinition &/*unused*/) const
|
||||
{
|
||||
return QStringLiteral("polygon");
|
||||
}
|
||||
|
||||
QString
|
||||
MySqlSchemaGrammar::typeGeometryCollection(const ColumnDefinition &/*unused*/) const
|
||||
{
|
||||
return QStringLiteral("geometrycollection");
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::typeMultiPoint(const ColumnDefinition &/*unused*/) const
|
||||
{
|
||||
return QStringLiteral("multipoint");
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::typeMultiLineString(const ColumnDefinition &/*unused*/) const
|
||||
{
|
||||
return QStringLiteral("multilinestring");
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::typeMultiPolygon(const ColumnDefinition &/*unused*/) const
|
||||
{
|
||||
return QStringLiteral("multipolygon");
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::typeComputed(const ColumnDefinition &/*unused*/) const
|
||||
{
|
||||
throw Exceptions::RuntimeError(
|
||||
"This database driver requires a type, see the virtualAs / storedAs "
|
||||
"modifiers.");
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::modifyVirtualAs(const ColumnDefinition &column) const
|
||||
{
|
||||
if (column.virtualAs.isEmpty())
|
||||
return {};
|
||||
|
||||
return QStringLiteral(" as (%1)").arg(column.virtualAs);
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::modifyStoredAs(const ColumnDefinition &column) const
|
||||
{
|
||||
if (column.storedAs.isEmpty())
|
||||
return {};
|
||||
|
||||
return QStringLiteral(" as (%1) stored").arg(column.storedAs);
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::modifyUnsigned(const ColumnDefinition &column) const
|
||||
{
|
||||
if (!column.isUnsigned)
|
||||
return {};
|
||||
|
||||
return QStringLiteral(" unsigned");
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::modifyCharset(const ColumnDefinition &column) const
|
||||
{
|
||||
if (column.charset.isEmpty())
|
||||
return {};
|
||||
|
||||
// CUR check quote, origin doesn't have silverqx
|
||||
return QStringLiteral(" character set %1").arg(quoteString(column.charset));
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::modifyCollate(const ColumnDefinition &column) const
|
||||
{
|
||||
if (column.collation.isEmpty())
|
||||
return {};
|
||||
|
||||
return QStringLiteral(" collate %1").arg(quoteString(column.collation));
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::modifyNullable(const ColumnDefinition &column) const
|
||||
{
|
||||
static const auto notNull = QStringLiteral(" not null");
|
||||
|
||||
if (column.virtualAs.isEmpty() && column.storedAs.isEmpty())
|
||||
return column.nullable ? QStringLiteral(" null") : notNull;
|
||||
|
||||
// CUR schema, find out why set 'not null' only for virtual/stored silverqx
|
||||
// Don't set null for virtual/stored columns, set 'not null' only
|
||||
if (column.nullable)
|
||||
return {};
|
||||
|
||||
return notNull;
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::modifyInvisible(const ColumnDefinition &column) const
|
||||
{
|
||||
if (!column.invisible)
|
||||
return {};
|
||||
|
||||
return QStringLiteral(" invisible");
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::modifyDefault(const ColumnDefinition &column) const
|
||||
{
|
||||
const auto &defaultValue = column.defaultValue;
|
||||
|
||||
if (!defaultValue.isValid() || defaultValue.isNull())
|
||||
return {};
|
||||
|
||||
// CUR schema, note about security in docs, unprepared and unescaped silverqx
|
||||
return QStringLiteral(" default %1").arg(getDefaultValue(defaultValue));
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::modifyIncrement(const ColumnDefinition &column) const
|
||||
{
|
||||
static const std::unordered_set serials {
|
||||
ColumnType::BigInteger, ColumnType::Integer, ColumnType::MediumInteger,
|
||||
ColumnType::SmallInteger, ColumnType::TinyInteger
|
||||
};
|
||||
|
||||
// This reverse OR algebra is sick 😮🙃
|
||||
if (!column.autoIncrement || !serials.contains(column.type))
|
||||
return {};
|
||||
|
||||
return QStringLiteral(" auto_increment primary key");
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::modifyFirst(const ColumnDefinition &column) const
|
||||
{
|
||||
if (!column.first)
|
||||
return {};
|
||||
|
||||
return QStringLiteral(" first");
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::modifyAfter(const ColumnDefinition &column) const
|
||||
{
|
||||
if (column.after.isEmpty())
|
||||
return {};
|
||||
|
||||
return QStringLiteral(" after %1").arg(BaseGrammar::wrap(column.after));
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::modifyComment(const ColumnDefinition &column) const
|
||||
{
|
||||
if (column.comment.isEmpty())
|
||||
return {};
|
||||
|
||||
// CUR schema docs, note about escaping silverqx
|
||||
// All escaped special characters will be correctly saved in the comment
|
||||
return QStringLiteral(" comment %1").arg(quoteString(addSlashes(column.comment)));
|
||||
}
|
||||
|
||||
QString MySqlSchemaGrammar::modifySrid(const ColumnDefinition &column) const
|
||||
{
|
||||
if (const auto &srid = column.srid;
|
||||
srid && *srid > 0
|
||||
)
|
||||
return QStringLiteral(" srid %1").arg(*srid);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace Orm::SchemaNs::Grammars
|
||||
|
||||
TINYORM_END_COMMON_NAMESPACE
|
||||
|
||||
@@ -1,10 +1,24 @@
|
||||
#include "orm/schema/grammars/postgresschemagrammar.hpp"
|
||||
|
||||
#include "orm/exceptions/runtimeerror.hpp"
|
||||
|
||||
TINYORM_BEGIN_COMMON_NAMESPACE
|
||||
|
||||
namespace Orm::Schema::Grammars
|
||||
namespace Orm::SchemaNs::Grammars
|
||||
{
|
||||
|
||||
/* Compile methods for the SchemaBuilder */
|
||||
|
||||
QString PostgresSchemaGrammar::compileEnableForeignKeyConstraints() const
|
||||
{
|
||||
throw Exceptions::RuntimeError(NotImplemented);
|
||||
}
|
||||
|
||||
QString PostgresSchemaGrammar::compileDisableForeignKeyConstraints() const
|
||||
{
|
||||
throw Exceptions::RuntimeError(NotImplemented);
|
||||
}
|
||||
|
||||
QString PostgresSchemaGrammar::compileColumnListing(const QString &/*unused*/) const
|
||||
{
|
||||
return QStringLiteral("select column_name "
|
||||
@@ -12,6 +26,34 @@ QString PostgresSchemaGrammar::compileColumnListing(const QString &/*unused*/) c
|
||||
"where table_schema = ? and table_name = ?");
|
||||
}
|
||||
|
||||
} // namespace Orm::Schema::Grammars
|
||||
/* Compile methods for commands */
|
||||
|
||||
QVector<QString>
|
||||
PostgresSchemaGrammar::compileForeign(const Blueprint &/*unused*/,
|
||||
const ColumnDefinition &/*unused*/) const
|
||||
{
|
||||
throw Exceptions::RuntimeError(NotImplemented);
|
||||
}
|
||||
|
||||
QVector<QString>
|
||||
PostgresSchemaGrammar::invokeCompileMethod(const ColumnDefinition &/*unused*/,
|
||||
const DatabaseConnection &/*unused*/,
|
||||
const Blueprint &/*unused*/) const
|
||||
{
|
||||
throw Exceptions::RuntimeError(NotImplemented);
|
||||
}
|
||||
|
||||
QString PostgresSchemaGrammar::addModifiers(QString &&/*unused*/,
|
||||
const ColumnDefinition &/*unused*/) const
|
||||
{
|
||||
throw Exceptions::RuntimeError(NotImplemented);
|
||||
}
|
||||
|
||||
QString PostgresSchemaGrammar::getType(const ColumnDefinition &/*unused*/) const
|
||||
{
|
||||
throw Exceptions::RuntimeError(NotImplemented);
|
||||
}
|
||||
|
||||
} // namespace Orm::SchemaNs::Grammars
|
||||
|
||||
TINYORM_END_COMMON_NAMESPACE
|
||||
|
||||
156
src/orm/schema/grammars/schemagrammar.cpp
Normal file
156
src/orm/schema/grammars/schemagrammar.cpp
Normal file
@@ -0,0 +1,156 @@
|
||||
#include "orm/schema/grammars/schemagrammar.hpp"
|
||||
|
||||
#include "orm/databaseconnection.hpp"
|
||||
#include "orm/exceptions/invalidargumenterror.hpp"
|
||||
#include "orm/schema/blueprint.hpp"
|
||||
|
||||
TINYORM_BEGIN_COMMON_NAMESPACE
|
||||
|
||||
namespace Orm::SchemaNs::Grammars
|
||||
{
|
||||
|
||||
QString SchemaGrammar::compileCreateDatabase(const QString &/*unused*/,
|
||||
DatabaseConnection &connection) const
|
||||
{
|
||||
throw Exceptions::LogicError(
|
||||
QStringLiteral("%1 database driver does not support creating databases.")
|
||||
.arg(connection.driverName()));
|
||||
}
|
||||
|
||||
QString SchemaGrammar::compileDropDatabaseIfExists(const QString &/*unused*/) const
|
||||
{
|
||||
throw Exceptions::LogicError(
|
||||
"This database driver does not support dropping databases.");
|
||||
}
|
||||
|
||||
QString SchemaGrammar::compileDropAllTables(const QVector<QString> &/*unused*/) const
|
||||
{
|
||||
throw Exceptions::RuntimeError(NotImplemented);
|
||||
}
|
||||
|
||||
QString SchemaGrammar::compileDropAllViews(const QVector<QString> &/*unused*/) const
|
||||
{
|
||||
throw Exceptions::RuntimeError(NotImplemented);
|
||||
}
|
||||
|
||||
QString SchemaGrammar::compileGetAllTables() const
|
||||
{
|
||||
throw Exceptions::RuntimeError(NotImplemented);
|
||||
}
|
||||
|
||||
QString SchemaGrammar::compileGetAllViews() const
|
||||
{
|
||||
throw Exceptions::RuntimeError(NotImplemented);
|
||||
}
|
||||
|
||||
QString SchemaGrammar::compileTableExists() const
|
||||
{
|
||||
throw Exceptions::RuntimeError(NotImplemented);
|
||||
}
|
||||
|
||||
QVector<QString>
|
||||
SchemaGrammar::compileFullText(const Blueprint &/*unused*/,
|
||||
const ColumnDefinition &/*unused*/) const
|
||||
{
|
||||
// CUR schema, check runtime vs logic exception silverqx
|
||||
// CUR schema, add driver and maybe connection names to this type of exceptions silverqx
|
||||
// CUR schema, extract this type of exceptions silverqx
|
||||
throw Exceptions::RuntimeError(
|
||||
"This database driver does not support dropping databases.");
|
||||
}
|
||||
|
||||
QVector<QString>
|
||||
SchemaGrammar::compileForeign(const Blueprint &blueprint,
|
||||
const ColumnDefinition &command) const
|
||||
{
|
||||
/* We need to prepare several of the elements of the foreign key definition
|
||||
before we can create the SQL, such as wrapping the tables and convert
|
||||
an array of columns to comma-delimited strings for the SQL queries. */
|
||||
auto sql = QStringLiteral("alter table %1 add constraint %2 ")
|
||||
.arg(wrapTable(blueprint), BaseGrammar::wrap(command.index));
|
||||
|
||||
/* Once we have the initial portion of the SQL statement we will add on the
|
||||
key name, table name, and referenced columns. These will complete the
|
||||
main portion of the SQL statement and this SQL will almost be done. */
|
||||
sql += QStringLiteral("foreign key (%1) references %2 (%3)")
|
||||
.arg(columnize(command.columns),
|
||||
BaseGrammar::wrapTable(command.on),
|
||||
columnize(command.references));
|
||||
|
||||
/* Once we have the basic foreign key creation statement constructed we can
|
||||
build out the syntax for what should happen on an update or delete of
|
||||
the affected columns, which will get something like "cascade", etc. */
|
||||
if (!command.onDelete.isEmpty())
|
||||
sql += QStringLiteral(" on delete %1").arg(command.onDelete);
|
||||
|
||||
if (!command.onUpdate.isEmpty())
|
||||
sql += QStringLiteral(" on update %1").arg(command.onUpdate);
|
||||
|
||||
return {sql};
|
||||
}
|
||||
|
||||
QVector<QString>
|
||||
SchemaGrammar::compileDropFullText(const Blueprint &/*unused*/,
|
||||
const ColumnDefinition &/*unused*/) const
|
||||
{
|
||||
throw Exceptions::RuntimeError(
|
||||
"This database driver does not support dropping databases.");
|
||||
}
|
||||
|
||||
QString SchemaGrammar::wrap(const ColumnDefinition &column, bool prefixAlias) const
|
||||
{
|
||||
return BaseGrammar::wrap(column.name, prefixAlias);
|
||||
}
|
||||
|
||||
QString SchemaGrammar::wrapTable(const Blueprint &blueprint) const
|
||||
{
|
||||
return BaseGrammar::wrapTable(blueprint.getTable());
|
||||
}
|
||||
|
||||
QStringList SchemaGrammar::getColumns(const Blueprint &blueprint) const
|
||||
{
|
||||
auto addedColumns = blueprint.getAddedColumns();
|
||||
|
||||
QStringList columns;
|
||||
columns.reserve(addedColumns.size());
|
||||
|
||||
for (auto &&column : addedColumns) {
|
||||
/* Each of the column types have their own compiler functions which are tasked
|
||||
with turning the column definition into its SQL format for this platform
|
||||
used by the connection. The column's modifiers are compiled and added. */
|
||||
auto sql = SPACE_IN.arg(wrap(column), getType(column));
|
||||
|
||||
columns << addModifiers(std::move(sql), column);
|
||||
}
|
||||
|
||||
return columns;
|
||||
}
|
||||
|
||||
QString SchemaGrammar::getDefaultValue(const QVariant &value) const
|
||||
{
|
||||
if (isExpression(value))
|
||||
return getValue(value).value<QString>();
|
||||
|
||||
if (!value.canConvert<QString>())
|
||||
throw Exceptions::InvalidArgumentError(
|
||||
"The default value has to be convertible to the QString.");
|
||||
|
||||
// Send boolean values as '0'/'1'
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
return value.typeId() == QMetaType::Bool
|
||||
#else
|
||||
return value.userType() == QMetaType::Bool
|
||||
#endif
|
||||
? quoteString(QString::number(value.value<int>()))
|
||||
: quoteString(value.value<QString>());
|
||||
}
|
||||
|
||||
QString SchemaGrammar::typeComputed(const ColumnDefinition &/*unused*/) const
|
||||
{
|
||||
throw Exceptions::RuntimeError(
|
||||
"This database driver does not support the computed type.");
|
||||
}
|
||||
|
||||
} // namespace Orm::SchemaNs::Grammars
|
||||
|
||||
TINYORM_END_COMMON_NAMESPACE
|
||||
@@ -1,10 +1,24 @@
|
||||
#include "orm/schema/grammars/sqliteschemagrammar.hpp"
|
||||
|
||||
#include "orm/exceptions/runtimeerror.hpp"
|
||||
|
||||
TINYORM_BEGIN_COMMON_NAMESPACE
|
||||
|
||||
namespace Orm::Schema::Grammars
|
||||
namespace Orm::SchemaNs::Grammars
|
||||
{
|
||||
|
||||
/* Compile methods for the SchemaBuilder */
|
||||
|
||||
QString SQLiteSchemaGrammar::compileEnableForeignKeyConstraints() const
|
||||
{
|
||||
throw Exceptions::RuntimeError(NotImplemented);
|
||||
}
|
||||
|
||||
QString SQLiteSchemaGrammar::compileDisableForeignKeyConstraints() const
|
||||
{
|
||||
throw Exceptions::RuntimeError(NotImplemented);
|
||||
}
|
||||
|
||||
QString SQLiteSchemaGrammar::compileColumnListing(const QString &table) const
|
||||
{
|
||||
auto table_ = table;
|
||||
@@ -12,9 +26,37 @@ QString SQLiteSchemaGrammar::compileColumnListing(const QString &table) const
|
||||
// TODO study, wtf is this 🤔 silverqx
|
||||
table_.replace(DOT, "__");
|
||||
|
||||
return QStringLiteral("pragma table_info(%1)").arg(wrap(table_));
|
||||
return QStringLiteral("pragma table_info(%1)").arg(BaseGrammar::wrap(table_));
|
||||
}
|
||||
|
||||
} // namespace Orm::Schema::Grammars
|
||||
/* Compile methods for commands */
|
||||
|
||||
QVector<QString>
|
||||
SQLiteSchemaGrammar::compileForeign(const Blueprint &/*unused*/,
|
||||
const ColumnDefinition &/*unused*/) const
|
||||
{
|
||||
throw Exceptions::RuntimeError(NotImplemented);
|
||||
}
|
||||
|
||||
QVector<QString>
|
||||
SQLiteSchemaGrammar::invokeCompileMethod(const ColumnDefinition &/*unused*/,
|
||||
const DatabaseConnection &/*unused*/,
|
||||
const Blueprint &/*unused*/) const
|
||||
{
|
||||
throw Exceptions::RuntimeError(NotImplemented);
|
||||
}
|
||||
|
||||
QString SQLiteSchemaGrammar::addModifiers(QString &&/*unused*/,
|
||||
const ColumnDefinition &/*unused*/) const
|
||||
{
|
||||
throw Exceptions::RuntimeError(NotImplemented);
|
||||
}
|
||||
|
||||
QString SQLiteSchemaGrammar::getType(const ColumnDefinition &/*unused*/) const
|
||||
{
|
||||
throw Exceptions::RuntimeError(NotImplemented);
|
||||
}
|
||||
|
||||
} // namespace Orm::SchemaNs::Grammars
|
||||
|
||||
TINYORM_END_COMMON_NAMESPACE
|
||||
|
||||
@@ -1,16 +1,89 @@
|
||||
#include "orm/schema/mysqlschemabuilder.hpp"
|
||||
|
||||
#include <QtSql/QSqlDriver>
|
||||
#include <QtSql/QSqlRecord>
|
||||
|
||||
#include "orm/databaseconnection.hpp"
|
||||
|
||||
TINYORM_BEGIN_COMMON_NAMESPACE
|
||||
|
||||
namespace Orm::Schema
|
||||
namespace Orm::SchemaNs
|
||||
{
|
||||
|
||||
QSqlQuery MySqlSchemaBuilder::createDatabase(const QString &name) const
|
||||
{
|
||||
return m_connection.statement(
|
||||
m_grammar.compileCreateDatabase(name, m_connection));
|
||||
}
|
||||
|
||||
QSqlQuery MySqlSchemaBuilder::dropDatabaseIfExists(const QString &name) const
|
||||
{
|
||||
return m_connection.statement(
|
||||
m_grammar.compileDropDatabaseIfExists(name));
|
||||
}
|
||||
|
||||
// CUR schema, test in functional tests silverqx
|
||||
void MySqlSchemaBuilder::dropAllTables() const
|
||||
{
|
||||
auto query = getAllTables();
|
||||
|
||||
// No fields in the record
|
||||
if (query.record().isEmpty())
|
||||
return;
|
||||
|
||||
QVector<QString> tables;
|
||||
if (const auto size = query.size(); size > 0)
|
||||
tables.reserve(size);
|
||||
|
||||
while (query.next())
|
||||
tables << query.value(0).value<QString>();
|
||||
|
||||
if (tables.isEmpty())
|
||||
return;
|
||||
|
||||
disableForeignKeyConstraints();
|
||||
|
||||
m_connection.statement(m_grammar.compileDropAllTables(tables));
|
||||
|
||||
enableForeignKeyConstraints();
|
||||
}
|
||||
|
||||
// CUR schema, test in functional tests silverqx
|
||||
void MySqlSchemaBuilder::dropAllViews() const
|
||||
{
|
||||
auto query = getAllViews();
|
||||
|
||||
// No fields in the record
|
||||
if (query.record().isEmpty())
|
||||
return;
|
||||
|
||||
QVector<QString> views;
|
||||
if (const auto size = query.size(); size > 0)
|
||||
views.reserve(size);
|
||||
|
||||
while (query.next())
|
||||
views << query.value(0).value<QString>();
|
||||
|
||||
if (views.isEmpty())
|
||||
return;
|
||||
|
||||
m_connection.statement(m_grammar.compileDropAllViews(views));
|
||||
}
|
||||
|
||||
QSqlQuery MySqlSchemaBuilder::getAllTables() const
|
||||
{
|
||||
// CUR schema, use postproccessor processColumnListing() silverqx
|
||||
return m_connection.select(m_grammar.compileGetAllTables());
|
||||
}
|
||||
|
||||
QSqlQuery MySqlSchemaBuilder::getAllViews() const
|
||||
{
|
||||
return m_connection.select(m_grammar.compileGetAllViews());
|
||||
}
|
||||
|
||||
QStringList MySqlSchemaBuilder::getColumnListing(const QString &table) const
|
||||
{
|
||||
const QString table_ = QStringLiteral("%1%2").arg(m_connection.getTablePrefix(),
|
||||
table);
|
||||
const auto table_ = NOSPACE.arg(m_connection.getTablePrefix(), table);
|
||||
|
||||
auto query = m_connection.select(m_grammar.compileColumnListing(), {
|
||||
m_connection.getDatabaseName(), table_
|
||||
@@ -19,6 +92,17 @@ QStringList MySqlSchemaBuilder::getColumnListing(const QString &table) const
|
||||
return m_connection.getPostProcessor().processColumnListing(query);
|
||||
}
|
||||
|
||||
} // namespace Orm::Schema
|
||||
bool MySqlSchemaBuilder::hasTable(const QString &table) const
|
||||
{
|
||||
const auto table_ = NOSPACE.arg(m_connection.getTablePrefix(), table);
|
||||
|
||||
Q_ASSERT(m_connection.driver()->hasFeature(QSqlDriver::QuerySize));
|
||||
|
||||
return m_connection.select(m_grammar.compileTableExists(),
|
||||
{m_connection.getDatabaseName(), table_})
|
||||
.size() > 0;
|
||||
}
|
||||
|
||||
} // namespace Orm::SchemaNs
|
||||
|
||||
TINYORM_END_COMMON_NAMESPACE
|
||||
|
||||
@@ -4,14 +4,14 @@
|
||||
|
||||
TINYORM_BEGIN_COMMON_NAMESPACE
|
||||
|
||||
namespace Orm::Schema
|
||||
namespace Orm::SchemaNs
|
||||
{
|
||||
|
||||
QStringList PostgresSchemaBuilder::getColumnListing(const QString &table) const
|
||||
{
|
||||
auto [schema, table_] = parseSchemaAndTable(table);
|
||||
|
||||
table_ = QStringLiteral("%1%2").arg(m_connection.getTablePrefix(), table);
|
||||
table_ = NOSPACE.arg(m_connection.getTablePrefix(), table);
|
||||
|
||||
auto query = m_connection.select(m_grammar.compileColumnListing(), {
|
||||
schema, table_
|
||||
@@ -45,6 +45,6 @@ PostgresSchemaBuilder::parseSchemaAndTable(const QString &table) const
|
||||
return {std::move(schema), table};
|
||||
}
|
||||
|
||||
} // namespace Orm::Schema
|
||||
} // namespace Orm::SchemaNs
|
||||
|
||||
TINYORM_END_COMMON_NAMESPACE
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
#include "orm/schema/schemabuilder.hpp"
|
||||
|
||||
#include <range/v3/action/transform.hpp>
|
||||
#include <range/v3/algorithm/contains.hpp>
|
||||
|
||||
#include "orm/databaseconnection.hpp"
|
||||
#include "orm/exceptions/logicerror.hpp"
|
||||
|
||||
TINYORM_BEGIN_COMMON_NAMESPACE
|
||||
|
||||
namespace Orm::Schema
|
||||
namespace Orm::SchemaNs
|
||||
{
|
||||
|
||||
SchemaBuilder::SchemaBuilder(DatabaseConnection &connection)
|
||||
@@ -12,6 +16,138 @@ SchemaBuilder::SchemaBuilder(DatabaseConnection &connection)
|
||||
, m_grammar(connection.getSchemaGrammar())
|
||||
{}
|
||||
|
||||
QSqlQuery SchemaBuilder::createDatabase(const QString &/*unused*/) const
|
||||
{
|
||||
throw Exceptions::LogicError(
|
||||
QStringLiteral("%1 database driver does not support creating databases.")
|
||||
.arg(m_connection.driverName()));
|
||||
}
|
||||
|
||||
QSqlQuery SchemaBuilder::dropDatabaseIfExists(const QString &/*unused*/) const
|
||||
{
|
||||
throw Exceptions::LogicError(
|
||||
"This database driver does not support dropping databases.");
|
||||
}
|
||||
|
||||
void SchemaBuilder::create(const QString &table,
|
||||
const std::function<void(Blueprint &)> &callback) const
|
||||
{
|
||||
auto blueprint = createBlueprint(table);
|
||||
|
||||
blueprint.create();
|
||||
|
||||
std::invoke(callback, blueprint);
|
||||
|
||||
build(std::move(blueprint));
|
||||
}
|
||||
|
||||
void SchemaBuilder::table(const QString &table,
|
||||
const std::function<void(Blueprint &)> &callback) const
|
||||
{
|
||||
build(createBlueprint(table, callback));
|
||||
}
|
||||
|
||||
void SchemaBuilder::drop(const QString &table) const
|
||||
{
|
||||
// CUR schema, create tap helper silverqx
|
||||
auto blueprint = createBlueprint(table);
|
||||
|
||||
blueprint.drop();
|
||||
|
||||
build(std::move(blueprint));
|
||||
}
|
||||
|
||||
void SchemaBuilder::dropIfExists(const QString &table) const
|
||||
{
|
||||
auto blueprint = createBlueprint(table);
|
||||
|
||||
blueprint.dropIfExists();
|
||||
|
||||
build(std::move(blueprint));
|
||||
}
|
||||
|
||||
void SchemaBuilder::rename(const QString &from, const QString &to) const
|
||||
{
|
||||
auto blueprint = createBlueprint(from);
|
||||
|
||||
blueprint.rename(to);
|
||||
|
||||
build(std::move(blueprint));
|
||||
}
|
||||
|
||||
void SchemaBuilder::dropColumns(const QString &table,
|
||||
const QVector<QString> &columns) const
|
||||
{
|
||||
auto blueprint = createBlueprint(table);
|
||||
|
||||
blueprint.dropColumns(columns);
|
||||
|
||||
build(std::move(blueprint));
|
||||
}
|
||||
|
||||
void SchemaBuilder::dropColumn(const QString &table, const QString &column) const
|
||||
{
|
||||
auto blueprint = createBlueprint(table);
|
||||
|
||||
blueprint.dropColumns({column});
|
||||
|
||||
build(std::move(blueprint));
|
||||
}
|
||||
|
||||
void SchemaBuilder::renameColumn(const QString &table, const QString &from,
|
||||
const QString &to)
|
||||
{
|
||||
auto blueprint = createBlueprint(table);
|
||||
|
||||
blueprint.renameColumn(from, to);
|
||||
|
||||
build(std::move(blueprint));
|
||||
}
|
||||
|
||||
void SchemaBuilder::dropAllTables() const
|
||||
{
|
||||
// CUR schema, solve this logic vs runtime exception silverqx
|
||||
throw Exceptions::LogicError(
|
||||
QStringLiteral("%1 database driver does not support dropping all tables.")
|
||||
.arg(m_connection.driverName()));
|
||||
}
|
||||
|
||||
void SchemaBuilder::dropAllViews() const
|
||||
{
|
||||
throw Exceptions::LogicError(
|
||||
QStringLiteral("%1 database driver does not support dropping all views.")
|
||||
.arg(m_connection.driverName()));
|
||||
}
|
||||
|
||||
void SchemaBuilder::dropAllTypes() const
|
||||
{
|
||||
throw Exceptions::LogicError(
|
||||
QStringLiteral("%1 database driver does not support dropping all types.")
|
||||
.arg(m_connection.driverName()));
|
||||
}
|
||||
|
||||
QSqlQuery SchemaBuilder::getAllTables() const
|
||||
{
|
||||
throw Exceptions::LogicError(
|
||||
QStringLiteral("%1 database driver does not support getting all tables.")
|
||||
.arg(m_connection.driverName()));
|
||||
}
|
||||
|
||||
QSqlQuery SchemaBuilder::getAllViews() const
|
||||
{
|
||||
throw Exceptions::RuntimeError(NotImplemented);
|
||||
}
|
||||
|
||||
QSqlQuery SchemaBuilder::enableForeignKeyConstraints() const
|
||||
{
|
||||
return m_connection.statement(m_grammar.compileEnableForeignKeyConstraints());
|
||||
}
|
||||
|
||||
QSqlQuery SchemaBuilder::disableForeignKeyConstraints() const
|
||||
{
|
||||
return m_connection.statement(m_grammar.compileDisableForeignKeyConstraints());
|
||||
}
|
||||
|
||||
QStringList SchemaBuilder::getColumnListing(const QString &table) const
|
||||
{
|
||||
auto query = m_connection.selectFromWriteConnection(
|
||||
@@ -21,6 +157,52 @@ QStringList SchemaBuilder::getColumnListing(const QString &table) const
|
||||
return m_connection.getPostProcessor().processColumnListing(query);
|
||||
}
|
||||
|
||||
} // namespace Orm::Schema
|
||||
bool SchemaBuilder::hasTable(const QString &/*unused*/) const
|
||||
{
|
||||
throw Exceptions::RuntimeError(NotImplemented);
|
||||
}
|
||||
|
||||
// CUR schema, test in functional tests silverqx
|
||||
bool SchemaBuilder::hasColumn(const QString &table, const QString &column) const
|
||||
{
|
||||
return ranges::contains(getColumnListing(table), column.toLower(),
|
||||
[](auto &&columnFromListing)
|
||||
{
|
||||
return columnFromListing.toLower();
|
||||
});
|
||||
}
|
||||
|
||||
bool SchemaBuilder::hasColumns(const QString &table,
|
||||
const QVector<QString> &columns) const
|
||||
{
|
||||
auto columnsFromListing = getColumnListing(table);
|
||||
|
||||
columnsFromListing |= ranges::actions::transform([](const auto &column)
|
||||
{
|
||||
return column.toLower();
|
||||
});
|
||||
|
||||
return std::ranges::all_of(columns, [&columnsFromListing](const auto &column)
|
||||
{
|
||||
return columnsFromListing.contains(column.toLower());
|
||||
});
|
||||
}
|
||||
|
||||
Blueprint SchemaBuilder::createBlueprint(
|
||||
const QString &table, const std::function<void(Blueprint &)> &callback) const
|
||||
{
|
||||
auto prefix = m_connection.getConfig(prefix_indexes).value<bool>()
|
||||
? m_connection.getConfig(prefix_).value<QString>()
|
||||
: "";
|
||||
|
||||
return Blueprint(table, callback, std::move(prefix));
|
||||
}
|
||||
|
||||
void SchemaBuilder::build(Blueprint &&blueprint) const
|
||||
{
|
||||
blueprint.build(m_connection, m_grammar);
|
||||
}
|
||||
|
||||
} // namespace Orm::SchemaNs
|
||||
|
||||
TINYORM_END_COMMON_NAMESPACE
|
||||
|
||||
40
src/orm/schema/schemaconstants_extern.cpp
Normal file
40
src/orm/schema/schemaconstants_extern.cpp
Normal file
@@ -0,0 +1,40 @@
|
||||
#include "orm/schema/schemaconstants_extern.hpp"
|
||||
|
||||
TINYORM_BEGIN_COMMON_NAMESPACE
|
||||
|
||||
namespace Orm::SchemaNs::Constants
|
||||
{
|
||||
|
||||
// Command names
|
||||
const QString Create = QStringLiteral("create");
|
||||
const QString Add = QStringLiteral("add");
|
||||
const QString Change = QStringLiteral("change");
|
||||
const QString Drop = QStringLiteral("drop");
|
||||
const QString DropIfExists = QStringLiteral("dropIfExists");
|
||||
const QString Rename = QStringLiteral("rename");
|
||||
const QString DropColumn = QStringLiteral("dropColumn");
|
||||
const QString RenameColumn = QStringLiteral("renameColumn");
|
||||
const QString DropPrimary = QStringLiteral("dropPrimary");
|
||||
const QString DropUnique = QStringLiteral("dropUnique");
|
||||
const QString DropIndex = QStringLiteral("dropIndex");
|
||||
const QString DropFullText = QStringLiteral("dropFullText");
|
||||
const QString DropSpatialIndex = QStringLiteral("dropSpatialIndex");
|
||||
const QString DropForeign = QStringLiteral("dropForeign");
|
||||
const QString RenameIndex = QStringLiteral("renameIndex");
|
||||
|
||||
// Indexes
|
||||
const QString Primary = QStringLiteral("primary");
|
||||
const QString Unique = QStringLiteral("unique");
|
||||
const QString Index = QStringLiteral("index");
|
||||
const QString Fulltext = QStringLiteral("fulltext");
|
||||
const QString SpatialIndex = QStringLiteral("spatialIndex");
|
||||
const QString Foreign = QStringLiteral("foreign");
|
||||
|
||||
// Foreign constrains
|
||||
const QString Cascade = QStringLiteral("cascade");
|
||||
const QString Restrict = QStringLiteral("restrict");
|
||||
const QString SetNull = QStringLiteral("set null");
|
||||
|
||||
} // namespace Orm::SchemaNs::Constants
|
||||
|
||||
TINYORM_END_COMMON_NAMESPACE
|
||||
@@ -30,7 +30,7 @@ std::unique_ptr<SchemaBuilder> SQLiteConnection::getSchemaBuilder()
|
||||
if (!m_schemaGrammar)
|
||||
useDefaultSchemaGrammar();
|
||||
|
||||
return std::make_unique<Schema::SQLiteSchemaBuilder>(*this);
|
||||
return std::make_unique<SchemaNs::SQLiteSchemaBuilder>(*this);
|
||||
}
|
||||
|
||||
std::unique_ptr<QueryGrammar> SQLiteConnection::getDefaultQueryGrammar() const
|
||||
@@ -46,7 +46,7 @@ std::unique_ptr<QueryGrammar> SQLiteConnection::getDefaultQueryGrammar() const
|
||||
std::unique_ptr<SchemaGrammar> SQLiteConnection::getDefaultSchemaGrammar() const
|
||||
{
|
||||
// Ownership of a unique_ptr()
|
||||
auto grammar = std::make_unique<Schema::Grammars::SQLiteSchemaGrammar>();
|
||||
auto grammar = std::make_unique<SchemaNs::Grammars::SQLiteSchemaGrammar>();
|
||||
|
||||
withTablePrefix(*grammar);
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
extern_constants: \
|
||||
sourcesList += $$PWD/orm/constants_extern.cpp
|
||||
sourcesList += \
|
||||
$$PWD/orm/constants_extern.cpp \
|
||||
$$PWD/orm/schema/schemaconstants_extern.cpp
|
||||
|
||||
sourcesList += \
|
||||
$$PWD/orm/basegrammar.cpp \
|
||||
@@ -33,8 +35,13 @@ sourcesList += \
|
||||
$$PWD/orm/query/processors/processor.cpp \
|
||||
$$PWD/orm/query/processors/sqliteprocessor.cpp \
|
||||
$$PWD/orm/query/querybuilder.cpp \
|
||||
$$PWD/orm/schema.cpp \
|
||||
$$PWD/orm/schema/blueprint.cpp \
|
||||
$$PWD/orm/schema/foreignidcolumndefinitionreference.cpp \
|
||||
$$PWD/orm/schema/foreignkeydefinitionreference.cpp \
|
||||
$$PWD/orm/schema/grammars/mysqlschemagrammar.cpp \
|
||||
$$PWD/orm/schema/grammars/postgresschemagrammar.cpp \
|
||||
$$PWD/orm/schema/grammars/schemagrammar.cpp \
|
||||
$$PWD/orm/schema/grammars/sqliteschemagrammar.cpp \
|
||||
$$PWD/orm/schema/mysqlschemabuilder.cpp \
|
||||
$$PWD/orm/schema/postgresschemabuilder.cpp \
|
||||
|
||||
@@ -9,9 +9,11 @@ using Orm::Constants::driver_;
|
||||
using Orm::Constants::charset_;
|
||||
using Orm::Constants::check_database_exists;
|
||||
using Orm::Constants::collation_;
|
||||
using Orm::Constants::engine_;
|
||||
using Orm::Constants::foreign_key_constraints;
|
||||
using Orm::Constants::H127001;
|
||||
using Orm::Constants::host_;
|
||||
using Orm::Constants::InnoDB;
|
||||
using Orm::Constants::isolation_level;
|
||||
using Orm::Constants::options_;
|
||||
using Orm::Constants::P3306;
|
||||
@@ -19,6 +21,7 @@ using Orm::Constants::P5432;
|
||||
using Orm::Constants::password_;
|
||||
using Orm::Constants::port_;
|
||||
using Orm::Constants::prefix_;
|
||||
using Orm::Constants::prefix_indexes;
|
||||
using Orm::Constants::PUBLIC;
|
||||
using Orm::Constants::QMYSQL;
|
||||
using Orm::Constants::QPSQL;
|
||||
@@ -138,8 +141,10 @@ Databases::mysqlConfiguration()
|
||||
// Very important for tests
|
||||
{timezone_, "+00:00"},
|
||||
{prefix_, ""},
|
||||
{prefix_indexes, true},
|
||||
{strict_, true},
|
||||
{isolation_level, "REPEATABLE READ"},
|
||||
{engine_, InnoDB},
|
||||
{options_, QVariantHash()},
|
||||
// FUTURE remove, when unit tested silverqx
|
||||
// Example
|
||||
@@ -171,6 +176,8 @@ Databases::sqliteConfiguration()
|
||||
{foreign_key_constraints, qEnvironmentVariable("DB_SQLITE_FOREIGN_KEYS",
|
||||
QStringLiteral("true"))},
|
||||
{check_database_exists, true},
|
||||
{prefix_, ""},
|
||||
// FUTURE schema sqlite, prefix_indexes and sqlite, works it? test silverqx
|
||||
};
|
||||
|
||||
// Environment variables were undefined
|
||||
@@ -199,9 +206,10 @@ Databases::postgresConfiguration()
|
||||
{password_, qEnvironmentVariable("DB_PGSQL_PASSWORD", "")},
|
||||
{charset_, qEnvironmentVariable("DB_PGSQL_CHARSET", UTF8)},
|
||||
// I don't use timezone types in postgres anyway
|
||||
{timezone_, UTC},
|
||||
{prefix_, ""},
|
||||
{options_, QVariantHash()},
|
||||
{timezone_, UTC},
|
||||
{prefix_, ""},
|
||||
{prefix_indexes, true},
|
||||
{options_, QVariantHash()},
|
||||
};
|
||||
|
||||
// Environment variables were undefined
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
add_subdirectory(databaseconnection)
|
||||
add_subdirectory(query)
|
||||
add_subdirectory(schema)
|
||||
|
||||
if(ORM)
|
||||
add_subdirectory(tiny)
|
||||
|
||||
@@ -3,6 +3,7 @@ TEMPLATE = subdirs
|
||||
subdirsList = \
|
||||
databaseconnection \
|
||||
query \
|
||||
schema \
|
||||
version \
|
||||
|
||||
!disable_orm: \
|
||||
|
||||
@@ -177,6 +177,7 @@ void tst_MySql_QueryBuilder::get() const
|
||||
connection.query()->from("torrents").get({ID, NAME});
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -191,6 +192,7 @@ void tst_MySql_QueryBuilder::get() const
|
||||
connection.query()->from("torrents").get();
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -207,6 +209,7 @@ void tst_MySql_QueryBuilder::get_ColumnExpression() const
|
||||
connection.query()->from("torrents").get({Raw(ID), NAME});
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -222,6 +225,7 @@ void tst_MySql_QueryBuilder::find() const
|
||||
connection.query()->from("torrents").find(3, {ID, NAME});
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -239,6 +243,7 @@ void tst_MySql_QueryBuilder::find_ColumnAndValueExpression() const
|
||||
connection.query()->from("torrents").find(3, {ID, Raw(NAME)});
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -254,6 +259,7 @@ void tst_MySql_QueryBuilder::find_ColumnAndValueExpression() const
|
||||
connection.query()->from("torrents").find(Raw("1 + 3"), {ID, Raw(NAME)});
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -270,6 +276,7 @@ void tst_MySql_QueryBuilder::first() const
|
||||
connection.query()->from("torrents").first({ID, NAME});
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -285,6 +292,7 @@ void tst_MySql_QueryBuilder::first_ColumnExpression() const
|
||||
connection.query()->from("torrents").first({ID, Raw(NAME)});
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -300,6 +308,7 @@ void tst_MySql_QueryBuilder::value() const
|
||||
connection.query()->from("torrents").value(NAME);
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -315,6 +324,7 @@ void tst_MySql_QueryBuilder::value_ColumnExpression() const
|
||||
connection.query()->from("torrents").value(Raw(NAME));
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -330,6 +340,7 @@ void tst_MySql_QueryBuilder::count() const
|
||||
connection.query()->from("torrents").count();
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -346,6 +357,7 @@ void tst_MySql_QueryBuilder::count_Distinct() const
|
||||
connection.query()->from("torrents").distinct().count(SIZE);
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -361,6 +373,7 @@ void tst_MySql_QueryBuilder::count_Distinct() const
|
||||
connection.query()->from("torrents").distinct().count({SIZE, "note"});
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -376,6 +389,7 @@ void tst_MySql_QueryBuilder::count_Distinct() const
|
||||
connection.query()->from("torrents").distinct({SIZE, "note"}).count();
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -392,6 +406,7 @@ void tst_MySql_QueryBuilder::min_Aggregate() const
|
||||
connection.query()->from("torrents").min(SIZE);
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -407,6 +422,7 @@ void tst_MySql_QueryBuilder::min_Aggregate_ColumnExpression() const
|
||||
connection.query()->from("torrents").min(Raw(SIZE));
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -422,6 +438,7 @@ void tst_MySql_QueryBuilder::max_Aggregate() const
|
||||
connection.query()->from("torrents").max(SIZE);
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -437,6 +454,7 @@ void tst_MySql_QueryBuilder::sum_Aggregate() const
|
||||
connection.query()->from("torrents").sum(SIZE);
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -452,6 +470,7 @@ void tst_MySql_QueryBuilder::average_Aggregate() const
|
||||
connection.query()->from("torrents").avg(SIZE);
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -1937,6 +1956,7 @@ void tst_MySql_QueryBuilder::insert() const
|
||||
connection.query()->from("torrents").insert({{NAME, "xyz"}, {SIZE, 6}});
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -1955,6 +1975,7 @@ void tst_MySql_QueryBuilder::insert_WithExpression() const
|
||||
{"progress", DB::raw(2)}});
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -1973,6 +1994,7 @@ void tst_MySql_QueryBuilder::update() const
|
||||
.update({{NAME, "xyz"}, {SIZE, 6}});
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -1992,6 +2014,7 @@ void tst_MySql_QueryBuilder::update_WithExpression() const
|
||||
{"progress", DB::raw(2)}});
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -2009,6 +2032,7 @@ void tst_MySql_QueryBuilder::remove() const
|
||||
connection.query()->from("torrents").remove(2222);
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -2025,6 +2049,7 @@ void tst_MySql_QueryBuilder::remove_WithExpression() const
|
||||
connection.query()->from("torrents").remove(DB::raw(2223));
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
|
||||
@@ -140,6 +140,7 @@ void tst_PostgreSQL_QueryBuilder::get() const
|
||||
connection.query()->from("torrents").get({ID, NAME});
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -154,6 +155,7 @@ void tst_PostgreSQL_QueryBuilder::get() const
|
||||
connection.query()->from("torrents").get();
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -170,6 +172,7 @@ void tst_PostgreSQL_QueryBuilder::get_ColumnExpression() const
|
||||
connection.query()->from("torrents").get({Raw(ID), NAME});
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -185,6 +188,7 @@ void tst_PostgreSQL_QueryBuilder::find() const
|
||||
connection.query()->from("torrents").find(3, {ID, NAME});
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -202,6 +206,7 @@ void tst_PostgreSQL_QueryBuilder::find_ColumnAndValueExpression() const
|
||||
connection.query()->from("torrents").find(3, {ID, Raw(NAME)});
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -217,6 +222,7 @@ void tst_PostgreSQL_QueryBuilder::find_ColumnAndValueExpression() const
|
||||
connection.query()->from("torrents").find(Raw("1 + 3"), {ID, Raw(NAME)});
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -233,6 +239,7 @@ void tst_PostgreSQL_QueryBuilder::first() const
|
||||
connection.query()->from("torrents").first({ID, NAME});
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -248,6 +255,7 @@ void tst_PostgreSQL_QueryBuilder::first_ColumnExpression() const
|
||||
connection.query()->from("torrents").first({ID, Raw(NAME)});
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -263,6 +271,7 @@ void tst_PostgreSQL_QueryBuilder::value() const
|
||||
connection.query()->from("torrents").value(NAME);
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -278,6 +287,7 @@ void tst_PostgreSQL_QueryBuilder::value_ColumnExpression() const
|
||||
connection.query()->from("torrents").value(Raw(NAME));
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -1535,6 +1545,7 @@ void tst_PostgreSQL_QueryBuilder::insert() const
|
||||
connection.query()->from("torrents").insert({{NAME, "xyz"}, {SIZE, 6}});
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -1553,6 +1564,7 @@ void tst_PostgreSQL_QueryBuilder::insert_WithExpression() const
|
||||
{"progress", DB::raw(2)}});
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -1572,6 +1584,7 @@ void tst_PostgreSQL_QueryBuilder::update() const
|
||||
.update({{NAME, "xyz"}, {SIZE, 6}});
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -1591,6 +1604,7 @@ void tst_PostgreSQL_QueryBuilder::update_WithExpression() const
|
||||
{"progress", DB::raw(2)}});
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -1608,6 +1622,7 @@ void tst_PostgreSQL_QueryBuilder::remove() const
|
||||
connection.query()->from("torrents").remove(2222);
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -1624,6 +1639,7 @@ void tst_PostgreSQL_QueryBuilder::remove_WithExpression() const
|
||||
connection.query()->from("torrents").remove(DB::raw(2223));
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
|
||||
@@ -138,6 +138,7 @@ void tst_SQLite_QueryBuilder::get() const
|
||||
connection.query()->from("torrents").get({ID, NAME});
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -152,6 +153,7 @@ void tst_SQLite_QueryBuilder::get() const
|
||||
connection.query()->from("torrents").get();
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -168,6 +170,7 @@ void tst_SQLite_QueryBuilder::get_ColumnExpression() const
|
||||
connection.query()->from("torrents").get({Raw(ID), NAME});
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -183,6 +186,7 @@ void tst_SQLite_QueryBuilder::find() const
|
||||
connection.query()->from("torrents").find(3, {ID, NAME});
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -200,6 +204,7 @@ void tst_SQLite_QueryBuilder::find_ColumnAndValueExpression() const
|
||||
connection.query()->from("torrents").find(3, {ID, Raw(NAME)});
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -215,6 +220,7 @@ void tst_SQLite_QueryBuilder::find_ColumnAndValueExpression() const
|
||||
connection.query()->from("torrents").find(Raw("1 + 3"), {ID, Raw(NAME)});
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -231,6 +237,7 @@ void tst_SQLite_QueryBuilder::first() const
|
||||
connection.query()->from("torrents").first({ID, NAME});
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -246,6 +253,7 @@ void tst_SQLite_QueryBuilder::first_ColumnExpression() const
|
||||
connection.query()->from("torrents").first({ID, Raw(NAME)});
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -261,6 +269,7 @@ void tst_SQLite_QueryBuilder::value() const
|
||||
connection.query()->from("torrents").value(NAME);
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -276,6 +285,7 @@ void tst_SQLite_QueryBuilder::value_ColumnExpression() const
|
||||
connection.query()->from("torrents").value(Raw(NAME));
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -1488,6 +1498,7 @@ void tst_SQLite_QueryBuilder::insert() const
|
||||
connection.query()->from("torrents").insert({{NAME, "xyz"}, {SIZE, 6}});
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -1506,6 +1517,7 @@ void tst_SQLite_QueryBuilder::insert_WithExpression() const
|
||||
{"progress", DB::raw(2)}});
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -1525,6 +1537,7 @@ void tst_SQLite_QueryBuilder::update() const
|
||||
.update({{NAME, "xyz"}, {SIZE, 6}});
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -1544,6 +1557,7 @@ void tst_SQLite_QueryBuilder::update_WithExpression() const
|
||||
{"progress", DB::raw(2)}});
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -1561,6 +1575,7 @@ void tst_SQLite_QueryBuilder::remove() const
|
||||
connection.query()->from("torrents").remove(2222);
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
@@ -1577,6 +1592,7 @@ void tst_SQLite_QueryBuilder::remove_WithExpression() const
|
||||
connection.query()->from("torrents").remove(DB::raw(2223));
|
||||
});
|
||||
|
||||
QVERIFY(!log.isEmpty());
|
||||
const auto &firstLog = log.first();
|
||||
|
||||
QCOMPARE(log.size(), 1);
|
||||
|
||||
2
tests/auto/unit/orm/schema/CMakeLists.txt
Normal file
2
tests/auto/unit/orm/schema/CMakeLists.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
add_subdirectory(blueprint)
|
||||
add_subdirectory(mysql_schemabuilder)
|
||||
12
tests/auto/unit/orm/schema/blueprint/CMakeLists.txt
Normal file
12
tests/auto/unit/orm/schema/blueprint/CMakeLists.txt
Normal file
@@ -0,0 +1,12 @@
|
||||
project(blueprint
|
||||
LANGUAGES CXX
|
||||
)
|
||||
|
||||
add_executable(blueprint
|
||||
tst_blueprint.cpp
|
||||
)
|
||||
|
||||
add_test(NAME blueprint COMMAND blueprint)
|
||||
|
||||
include(TinyTestCommon)
|
||||
tiny_configure_test(blueprint)
|
||||
4
tests/auto/unit/orm/schema/blueprint/blueprint.pro
Normal file
4
tests/auto/unit/orm/schema/blueprint/blueprint.pro
Normal file
@@ -0,0 +1,4 @@
|
||||
include($$TINYORM_SOURCE_TREE/tests/qmake/common.pri)
|
||||
include($$TINYORM_SOURCE_TREE/tests/qmake/TinyUtils.pri)
|
||||
|
||||
SOURCES = tst_blueprint.cpp
|
||||
259
tests/auto/unit/orm/schema/blueprint/tst_blueprint.cpp
Normal file
259
tests/auto/unit/orm/schema/blueprint/tst_blueprint.cpp
Normal file
@@ -0,0 +1,259 @@
|
||||
#include <QCoreApplication>
|
||||
#include <QtTest>
|
||||
|
||||
#include "orm/db.hpp"
|
||||
#include "orm/schema/grammars/mysqlschemagrammar.hpp"
|
||||
|
||||
#include "databases.hpp"
|
||||
|
||||
using Orm::Constants::NAME;
|
||||
using Orm::Constants::SIZE;
|
||||
|
||||
using Orm::DB;
|
||||
|
||||
using Orm::SchemaNs::Blueprint;
|
||||
using Orm::SchemaNs::Grammars::MySqlSchemaGrammar;
|
||||
|
||||
using TestUtils::Databases;
|
||||
|
||||
class tst_Blueprint : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void initTestCase();
|
||||
|
||||
void index_DefaultNames() const;
|
||||
void index_DefaultNames_WithPrefix() const;
|
||||
|
||||
void dropIndex_ByColumns_DefaultNames() const;
|
||||
void dropIndex_ByColumns_DefaultNames_WithPrefix() const;
|
||||
|
||||
void dropIndex_ByIndexName() const;
|
||||
|
||||
void unsignedDecimal_WithTotalAndPlaces() const;
|
||||
|
||||
void removeColumn() const;
|
||||
|
||||
// NOLINTNEXTLINE(readability-redundant-access-specifiers)
|
||||
private:
|
||||
/*! Connection name used in this test case. */
|
||||
QString m_connection {};
|
||||
};
|
||||
|
||||
void tst_Blueprint::initTestCase()
|
||||
{
|
||||
m_connection = Databases::createConnection(Databases::MYSQL);
|
||||
|
||||
if (m_connection.isEmpty())
|
||||
QSKIP(QStringLiteral("%1 autotest skipped, environment variables "
|
||||
"for '%2' connection have not been defined.")
|
||||
.arg("tst_Blueprint", Databases::MYSQL).toUtf8().constData(), );
|
||||
}
|
||||
|
||||
void tst_Blueprint::index_DefaultNames() const
|
||||
{
|
||||
// Unique
|
||||
{
|
||||
Blueprint blueprint("torrents");
|
||||
blueprint.unique({NAME, "foo"});
|
||||
const auto &commands = blueprint.getCommands();
|
||||
|
||||
QCOMPARE(commands.first().index, "torrents_name_foo_unique");
|
||||
}
|
||||
// Index
|
||||
{
|
||||
Blueprint blueprint("torrents");
|
||||
blueprint.index(SIZE);
|
||||
const auto &commands = blueprint.getCommands();
|
||||
|
||||
QCOMPARE(commands.first().index, "torrents_size_index");
|
||||
}
|
||||
// SpatialIndex
|
||||
{
|
||||
Blueprint blueprint("torrents");
|
||||
blueprint.spatialIndex({"coordinates"});
|
||||
const auto &commands = blueprint.getCommands();
|
||||
|
||||
QCOMPARE(commands.first().index, "torrents_coordinates_spatialindex");
|
||||
}
|
||||
// FullText
|
||||
{
|
||||
Blueprint blueprint("torrents");
|
||||
blueprint.fullText("note");
|
||||
const auto &commands = blueprint.getCommands();
|
||||
|
||||
QCOMPARE(commands.first().index, "torrents_note_fulltext");
|
||||
}
|
||||
}
|
||||
|
||||
void tst_Blueprint::index_DefaultNames_WithPrefix() const
|
||||
{
|
||||
// Unique
|
||||
{
|
||||
Blueprint blueprint("torrents", nullptr, "prefix_");
|
||||
blueprint.unique({NAME, "foo"});
|
||||
const auto &commands = blueprint.getCommands();
|
||||
|
||||
QCOMPARE(commands.first().index, "prefix_torrents_name_foo_unique");
|
||||
}
|
||||
// Index
|
||||
{
|
||||
Blueprint blueprint("torrents", nullptr, "prefix_");
|
||||
blueprint.index(SIZE);
|
||||
const auto &commands = blueprint.getCommands();
|
||||
|
||||
QCOMPARE(commands.first().index, "prefix_torrents_size_index");
|
||||
}
|
||||
// SpatialIndex
|
||||
{
|
||||
Blueprint blueprint("torrents", nullptr, "prefix_");
|
||||
blueprint.spatialIndex({"coordinates"});
|
||||
const auto &commands = blueprint.getCommands();
|
||||
|
||||
QCOMPARE(commands.first().index, "prefix_torrents_coordinates_spatialindex");
|
||||
}
|
||||
// FullText
|
||||
{
|
||||
Blueprint blueprint("torrents", nullptr, "prefix_");
|
||||
blueprint.fullText("note");
|
||||
const auto &commands = blueprint.getCommands();
|
||||
|
||||
QCOMPARE(commands.first().index, "prefix_torrents_note_fulltext");
|
||||
}
|
||||
}
|
||||
|
||||
void tst_Blueprint::dropIndex_ByColumns_DefaultNames() const
|
||||
{
|
||||
{
|
||||
Blueprint blueprint("torrents");
|
||||
blueprint.dropUnique({NAME, "foo"});
|
||||
const auto &commands = blueprint.getCommands();
|
||||
|
||||
QCOMPARE(commands.first().index, "torrents_name_foo_unique");
|
||||
}
|
||||
// Index
|
||||
{
|
||||
Blueprint blueprint("torrents");
|
||||
blueprint.dropIndex(QVector<QString> {SIZE});
|
||||
const auto &commands = blueprint.getCommands();
|
||||
|
||||
QCOMPARE(commands.first().index, "torrents_size_index");
|
||||
}
|
||||
// SpatialIndex
|
||||
{
|
||||
Blueprint blueprint("torrents");
|
||||
blueprint.dropSpatialIndex({"coordinates"});
|
||||
const auto &commands = blueprint.getCommands();
|
||||
|
||||
QCOMPARE(commands.first().index, "torrents_coordinates_spatialindex");
|
||||
}
|
||||
// FullText
|
||||
{
|
||||
Blueprint blueprint("torrents");
|
||||
blueprint.dropFullText({"note"});
|
||||
const auto &commands = blueprint.getCommands();
|
||||
|
||||
QCOMPARE(commands.first().index, "torrents_note_fulltext");
|
||||
}
|
||||
}
|
||||
|
||||
void tst_Blueprint::dropIndex_ByColumns_DefaultNames_WithPrefix() const
|
||||
{
|
||||
{
|
||||
Blueprint blueprint("torrents", nullptr, "prefix_");
|
||||
blueprint.dropUnique({NAME, "foo"});
|
||||
const auto &commands = blueprint.getCommands();
|
||||
|
||||
QCOMPARE(commands.first().index, "prefix_torrents_name_foo_unique");
|
||||
}
|
||||
// Index
|
||||
{
|
||||
Blueprint blueprint("torrents", nullptr, "prefix_");
|
||||
blueprint.dropIndex(QVector<QString> {SIZE});
|
||||
const auto &commands = blueprint.getCommands();
|
||||
|
||||
QCOMPARE(commands.first().index, "prefix_torrents_size_index");
|
||||
}
|
||||
// SpatialIndex
|
||||
{
|
||||
Blueprint blueprint("torrents", nullptr, "prefix_");
|
||||
blueprint.dropSpatialIndex({"coordinates"});
|
||||
const auto &commands = blueprint.getCommands();
|
||||
|
||||
QCOMPARE(commands.first().index, "prefix_torrents_coordinates_spatialindex");
|
||||
}
|
||||
// FullText
|
||||
{
|
||||
Blueprint blueprint("torrents", nullptr, "prefix_");
|
||||
blueprint.dropFullText({"note"});
|
||||
const auto &commands = blueprint.getCommands();
|
||||
|
||||
QCOMPARE(commands.first().index, "prefix_torrents_note_fulltext");
|
||||
}
|
||||
}
|
||||
|
||||
void tst_Blueprint::dropIndex_ByIndexName() const
|
||||
{
|
||||
{
|
||||
Blueprint blueprint("torrents");
|
||||
blueprint.dropUnique(NAME);
|
||||
const auto &commands = blueprint.getCommands();
|
||||
|
||||
QCOMPARE(commands.first().index, NAME);
|
||||
}
|
||||
// Index
|
||||
{
|
||||
Blueprint blueprint("torrents");
|
||||
blueprint.dropIndex(SIZE);
|
||||
const auto &commands = blueprint.getCommands();
|
||||
|
||||
QCOMPARE(commands.first().index, SIZE);
|
||||
}
|
||||
// SpatialIndex
|
||||
{
|
||||
Blueprint blueprint("torrents");
|
||||
blueprint.dropSpatialIndex("coordinates");
|
||||
const auto &commands = blueprint.getCommands();
|
||||
|
||||
QCOMPARE(commands.first().index, "coordinates");
|
||||
}
|
||||
// FullText
|
||||
{
|
||||
Blueprint blueprint("torrents");
|
||||
blueprint.dropFullText("note");
|
||||
const auto &commands = blueprint.getCommands();
|
||||
|
||||
QCOMPARE(commands.first().index, "note");
|
||||
}
|
||||
}
|
||||
|
||||
void tst_Blueprint::unsignedDecimal_WithTotalAndPlaces() const
|
||||
{
|
||||
Blueprint blueprint("cars", [](Blueprint &table)
|
||||
{
|
||||
table.unsignedDecimal("money", 10, 2);
|
||||
});
|
||||
|
||||
QCOMPARE(blueprint.toSql(DB::connection(m_connection), MySqlSchemaGrammar()),
|
||||
QVector<QString> {"alter table `cars` "
|
||||
"add `money` decimal(10, 2) unsigned not null"});
|
||||
}
|
||||
|
||||
void tst_Blueprint::removeColumn() const
|
||||
{
|
||||
Blueprint blueprint("torrents", [](Blueprint &table)
|
||||
{
|
||||
table.string(NAME);
|
||||
table.integer(SIZE);
|
||||
table.removeColumn(SIZE);
|
||||
});
|
||||
|
||||
QCOMPARE(blueprint.toSql(DB::connection(m_connection), MySqlSchemaGrammar()),
|
||||
QVector<QString> {"alter table `torrents` "
|
||||
"add `name` varchar(255) not null"});
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_Blueprint)
|
||||
|
||||
#include "tst_blueprint.moc"
|
||||
@@ -0,0 +1,12 @@
|
||||
project(mysql_schemabuilder
|
||||
LANGUAGES CXX
|
||||
)
|
||||
|
||||
add_executable(mysql_schemabuilder
|
||||
tst_mysql_schemabuilder.cpp
|
||||
)
|
||||
|
||||
add_test(NAME mysql_schemabuilder COMMAND mysql_schemabuilder)
|
||||
|
||||
include(TinyTestCommon)
|
||||
tiny_configure_test(mysql_schemabuilder INCLUDE_MODELS)
|
||||
@@ -0,0 +1,5 @@
|
||||
include($$TINYORM_SOURCE_TREE/tests/qmake/common.pri)
|
||||
include($$TINYORM_SOURCE_TREE/tests/qmake/TinyUtils.pri)
|
||||
include($$TINYORM_SOURCE_TREE/tests/models/models.pri)
|
||||
|
||||
SOURCES = tst_mysql_schemabuilder.cpp
|
||||
File diff suppressed because it is too large
Load Diff
5
tests/auto/unit/orm/schema/schema.pro
Normal file
5
tests/auto/unit/orm/schema/schema.pro
Normal file
@@ -0,0 +1,5 @@
|
||||
TEMPLATE = subdirs
|
||||
|
||||
SUBDIRS = \
|
||||
blueprint \
|
||||
mysql_schemabuilder \
|
||||
Reference in New Issue
Block a user