Files
TinyORM/include/orm/schema/columndefinitionreference.hpp
T
silverqx 0bcbcd2431 added support for PostgreSQL schema builder 🎉👌
- added a new config. option dont_drop, allows to define table that
   will be excluded during dropAllTables(), has a default value
   spatial_ref_sys for PostGIS
 - implemented fluent commands, used only by the PostgreSQL Comment
   command
 - added tests for PostgreSQL schema builder
 - reworked tst_Migrate to be able to run on all supported connections,
   currently PostgreSQL and MySQL
 - updated docs

Unrelated:

 - added a new reference class IndexDefinitionReference for a nice API
   during index definition, contains algorithm and language
 - unified selectFromWriteConnection() in schema builders
2022-05-23 10:14:25 +02:00

392 lines
14 KiB
C++

#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;
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;
/*! Copy constructor. */
inline ColumnDefinitionReference(
const ColumnDefinitionReference &) = default;
/*! Move constructor. */
inline ColumnDefinitionReference(
ColumnDefinitionReference &&) noexcept = default;
/*! Deleted copy assignment operator. */
ColumnDefinitionReference &
operator=(const ColumnDefinitionReference &) = delete;
/*! Deleted move assignment operator. */
ColumnDefinitionReference &
operator=(ColumnDefinitionReference &&) noexcept = delete;
/*! Place the column "after" another column (MySQL). */
ColumnReferenceType &after(const QString &column);
/*! Used as a modifier for generatedAs() (PostgreSQL). */
ColumnReferenceType &always();
/*! 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);
/*! Create a SQL compliant identity column (PostgreSQL). */
ColumnReferenceType &generatedAs(const QString &expression);
/*! Specify that the column should be invisible to "SELECT *" (MySQL). */
ColumnReferenceType &invisible();
/*! Determine whether to use the geography (default, false) or
geometry type (PostgreSQL). */
ColumnReferenceType &isGeometry();
/*! Set the INTEGER column as UNSIGNED (MySQL). */
ColumnReferenceType &isUnsigned();
/*! Allow NULL values to be inserted into the column. */
ColumnReferenceType &nullable(bool value = true);
/*! The spatial reference identifier (SRID) of a geometry identifies the SRS
in which the geometry is defined (MySQL/PostgreSQL). */
ColumnReferenceType &srid(quint32 value);
/*! 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 = "");
protected:
/*! Reference to a column definition. */
std::reference_wrapper<ColumnDefinition> m_columnDefinition;
private:
/*! Static cast this to a child's instance type (CRTP). */
ColumnReferenceType &columnReference();
};
/* 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>::always()
{
m_columnDefinition.get().always = true;
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>::generatedAs(const QString &expression)
{
m_columnDefinition.get().generatedAs = expression;
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>::isGeometry()
{
m_columnDefinition.get().isGeometry = 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>::srid(const quint32 value)
{
m_columnDefinition.get().srid = value;
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