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:
silverqx
2022-03-22 09:53:33 +01:00
parent a7ace30999
commit a2714be30e
75 changed files with 6939 additions and 117 deletions

View File

@@ -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$'

View File

@@ -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

View File

@@ -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 \

View File

@@ -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

View File

@@ -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;

View File

@@ -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("=");

View File

@@ -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;

View File

@@ -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();

View File

@@ -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

View File

@@ -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
View 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

View 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 &&parameters = {});
/* 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 &&parameters = {});
/*! Create a new Fluent command.. */
ColumnDefinition createCommand(const QString &name,
ColumnDefinition &&parameters = {});
/*! 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

View 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

View 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

View 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

View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View 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

View 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

View 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

View 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

View File

@@ -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

View File

@@ -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__

View File

@@ -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

View File

@@ -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)...);

View File

@@ -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

View File

@@ -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. */

View 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

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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("=");

View File

@@ -367,6 +367,11 @@ bool DatabaseConnection::pingDatabase()
.arg(driverName()));
}
QSqlDriver *DatabaseConnection::driver()
{
return getQtConnection().driver();
}
void DatabaseConnection::reconnect() const
{
if (!m_reconnector)

View File

@@ -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_();

View File

@@ -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();

View File

@@ -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);

View File

@@ -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);

View File

@@ -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

View File

@@ -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

View File

@@ -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> &

View File

@@ -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
View 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

View 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 &&parameters)
{
// 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 &&parameters)
{
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 &&parameters)
{
// 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

View 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

View 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

View File

@@ -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

View File

@@ -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

View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View 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

View File

@@ -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);

View File

@@ -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 \

View File

@@ -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

View File

@@ -1,5 +1,6 @@
add_subdirectory(databaseconnection)
add_subdirectory(query)
add_subdirectory(schema)
if(ORM)
add_subdirectory(tiny)

View File

@@ -3,6 +3,7 @@ TEMPLATE = subdirs
subdirsList = \
databaseconnection \
query \
schema \
version \
!disable_orm: \

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -0,0 +1,2 @@
add_subdirectory(blueprint)
add_subdirectory(mysql_schemabuilder)

View 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)

View 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

View 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"

View File

@@ -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)

View File

@@ -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

View File

@@ -0,0 +1,5 @@
TEMPLATE = subdirs
SUBDIRS = \
blueprint \
mysql_schemabuilder \