renamed column_generator to column_definition_generator and column_name_generator to column_generator

This commit is contained in:
Sascha Kühl 2024-03-27 15:15:45 +01:00
parent be9f66c427
commit 50a0eb580a
18 changed files with 429 additions and 352 deletions

View File

@ -16,26 +16,17 @@ enum class sql_function_t {
struct column
{
column(const char *name) : name(name) {} // NOLINT(*-explicit-constructor)
column(std::string name) : name(std::move(name)) {} // NOLINT(*-explicit-constructor)
column(sql_function_t func, std::string name) : name(std::move(name)), function_(func) {} // NOLINT(*-explicit-constructor)
column(std::string table_name, std::string name, std::string as)
: table(std::move(table_name))
, name(std::move(name))
, alias(std::move(as)) {}
column(std::string table_name, const char* name, std::string as)
: table(std::move(table_name))
, name(name)
, alias(std::move(as)) {}
column(const char *name); // NOLINT(*-explicit-constructor)
column(std::string name); // NOLINT(*-explicit-constructor)
column(sql_function_t func, std::string name); // NOLINT(*-explicit-constructor)
column(std::string table_name, std::string name, std::string as);
column(std::string table_name, const char* name, std::string as);
column& as(std::string a) {
alias = std::move(a);
return *this;
}
bool equals(const column &x) const;
[[nodiscard]] bool is_function() const {
return function_ != sql_function_t::NONE;
}
column& as(std::string a);
[[nodiscard]] bool is_function() const;
std::string table;
std::string name;

View File

@ -0,0 +1,129 @@
#ifndef QUERY_COLUMN_DEFINITION_GENERATOR_HPP
#define QUERY_COLUMN_DEFINITION_GENERATOR_HPP
#include "matador/sql/column_definition.hpp"
#include "matador/sql/data_type_traits.hpp"
#include "matador/utils/access.hpp"
#include "matador/utils/field_attributes.hpp"
#include "matador/utils/foreign_attributes.hpp"
#include <typeindex>
#include <vector>
namespace matador::sql {
class schema;
class fk_column_generator
{
public:
fk_column_generator() = default;
template<class Type>
column_definition generate(const char *id, Type &x, const std::string &ref_table, const std::string &ref_column)
{
utils::access::process(*this, x);
return column_definition{id, type_, 0, ref_table, ref_column, {utils::constraints::FOREIGN_KEY }, null_option::NOT_NULL};
}
template<typename ValueType>
void on_primary_key(const char *, ValueType &/*pk*/, typename std::enable_if<std::is_integral<ValueType>::value && !std::is_same<bool, ValueType>::value>::type* = 0)
{
type_ = data_type_traits<ValueType>::builtin_type(0);
}
void on_primary_key(const char * /*id*/, std::string &/*pk*/, size_t size);
void on_revision(const char * /*id*/, unsigned long long &/*rev*/) {}
template < class Type >
void on_attribute(const char * /*id*/, Type &/*x*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
void on_attribute(const char * /*id*/, char * /*x*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
template<class Pointer>
void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {}
template<class Pointer>
void on_has_one(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {}
template<class ContainerType>
void on_has_many(const char *, ContainerType &, const char *, const char *, const utils::foreign_attributes &/*attr*/) {}
template<class ContainerType>
void on_has_many(const char *, ContainerType &, const utils::foreign_attributes &/*attr*/) {}
private:
data_type_t type_{};
};
class column_definition_generator
{
private:
column_definition_generator(std::vector<column_definition> &columns, const schema &repo);
public:
~column_definition_generator() = default;
template < class Type >
static std::vector<column_definition> generate(const schema &repo)
{
std::vector<column_definition> columns;
column_definition_generator gen(columns, repo);
Type obj;
matador::utils::access::process(gen, obj);
return std::move(columns);
}
template < class V >
void on_primary_key(const char *, V &x, typename std::enable_if<std::is_integral<V>::value && !std::is_same<bool, V>::value>::type* = 0);
void on_primary_key(const char *id, std::string &pk, size_t size);
void on_revision(const char *id, unsigned long long &rev);
template<typename Type>
void on_attribute(const char *id, Type &x, const utils::field_attributes &attr = utils::null_attributes);
template<typename Type>
void on_attribute(const char *id, std::optional<Type> &x, const utils::field_attributes &attr = utils::null_attributes);
template<class Pointer>
void on_belongs_to(const char *id, Pointer &x, const utils::foreign_attributes &/*attr*/)
{
const auto [ref_table, ref_column] = determine_foreign_ref(std::type_index(typeid(typename Pointer::value_type)));
columns_.push_back(fk_column_generator_.generate(id, *x, ref_table, ref_column));
}
template<class Pointer>
void on_has_one(const char *id, Pointer &x, const utils::foreign_attributes &/*attr*/)
{
const auto [ref_table, ref_column] = determine_foreign_ref(std::type_index(typeid(typename Pointer::value_type)));
columns_.push_back(fk_column_generator_.generate(id, *x, ref_table, ref_column));
}
template<class ContainerType>
void on_has_many(const char *, ContainerType &, const char *, const char *, const utils::foreign_attributes &/*attr*/) {}
template<class ContainerType>
void on_has_many(const char *, ContainerType &, const utils::foreign_attributes &/*attr*/) {}
private:
std::pair<std::string, std::string> determine_foreign_ref(const std::type_index &ti);
private:
size_t index_ = 0;
std::vector<column_definition> &columns_;
const schema &repo_;
fk_column_generator fk_column_generator_;
};
template<typename V>
void column_definition_generator::on_primary_key(const char *id, V &x, typename std::enable_if<std::is_integral<V>::value && !std::is_same<bool, V>::value>::type*)
{
on_attribute(id, x, { utils::constraints::PRIMARY_KEY });
}
template<typename Type>
void column_definition_generator::on_attribute(const char *id, Type &x, const utils::field_attributes &attr)
{
columns_.emplace_back(id, x, attr, null_option::NOT_NULL);
}
template<typename Type>
void column_definition_generator::on_attribute(const char *id, std::optional<Type> &x, const utils::field_attributes &attr)
{
columns_.emplace_back(id, data_type_traits<Type>::builtin_type(attr.size()), attr, null_option::NULLABLE);
}
}
#endif //QUERY_COLUMN_DEFINITION_GENERATOR_HPP

View File

@ -1,129 +1,119 @@
#ifndef QUERY_COLUMN_GENERATOR_HPP
#define QUERY_COLUMN_GENERATOR_HPP
#include "matador/sql/column_definition.hpp"
#include "matador/sql/data_type_traits.hpp"
#include "matador/utils/access.hpp"
#include "matador/utils/field_attributes.hpp"
#include "matador/utils/foreign_attributes.hpp"
#include <typeindex>
#include "matador/sql/column.hpp"
#include "matador/sql/schema.hpp"
#include <string>
#include <vector>
#include <stack>
namespace matador::sql {
class schema;
class fk_column_generator
{
public:
fk_column_generator() = default;
template<class Type>
column_definition generate(const char *id, Type &x, const std::string &ref_table, const std::string &ref_column)
{
utils::access::process(*this, x);
return column_definition{id, type_, 0, ref_table, ref_column, {utils::constraints::FOREIGN_KEY }, null_option::NOT_NULL};
}
template<typename ValueType>
void on_primary_key(const char *, ValueType &/*pk*/, typename std::enable_if<std::is_integral<ValueType>::value && !std::is_same<bool, ValueType>::value>::type* = 0)
{
type_ = data_type_traits<ValueType>::builtin_type(0);
}
void on_primary_key(const char * /*id*/, std::string &/*pk*/, size_t size);
void on_revision(const char * /*id*/, unsigned long long &/*rev*/) {}
template < class Type >
void on_attribute(const char * /*id*/, Type &/*x*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
void on_attribute(const char * /*id*/, char * /*x*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
template<class Pointer>
void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {}
template<class Pointer>
void on_has_one(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {}
template<class ContainerType>
void on_has_many(const char *, ContainerType &, const char *, const char *, const utils::foreign_attributes &/*attr*/) {}
template<class ContainerType>
void on_has_many(const char *, ContainerType &, const utils::foreign_attributes &/*attr*/) {}
private:
data_type_t type_{};
};
class column_generator
{
private:
column_generator(std::vector<column_definition> &columns, const schema &repo);
column_generator(std::vector<column> &column_infos, const sql::schema &ts, const std::string &table_name);
public:
~column_generator() = default;
template < class Type >
static std::vector<column_definition> generate(const schema &repo)
static std::vector<column> generate(const sql::schema &ts)
{
std::vector<column_definition> columns;
column_generator gen(columns, repo);
const auto info = ts.info<Type>();
if (!info) {
return {};
}
std::vector<column> columns;
column_generator gen(columns, ts, info.value().name);
Type obj;
matador::utils::access::process(gen, obj);
return std::move(columns);
}
template < class V >
void on_primary_key(const char *, V &x, typename std::enable_if<std::is_integral<V>::value && !std::is_same<bool, V>::value>::type* = 0);
void on_primary_key(const char *id, std::string &pk, size_t size);
void on_revision(const char *id, unsigned long long &rev);
void on_primary_key(const char *id, V &, typename std::enable_if<std::is_integral<V>::value && !std::is_same<bool, V>::value>::type* = 0)
{
push(id);
}
void on_primary_key(const char *id, std::string &, size_t);
void on_revision(const char *id, unsigned long long &/*rev*/);
template<typename Type>
void on_attribute(const char *id, Type &x, const utils::field_attributes &attr = utils::null_attributes);
template<typename Type>
void on_attribute(const char *id, std::optional<Type> &x, const utils::field_attributes &attr = utils::null_attributes);
void on_attribute(const char *id, Type &, const utils::field_attributes &/*attr*/ = utils::null_attributes)
{
push(id);
}
template<class Pointer>
void on_belongs_to(const char *id, Pointer &x, const utils::foreign_attributes &/*attr*/)
void on_belongs_to(const char *id, Pointer &, const utils::foreign_attributes &attr)
{
const auto [ref_table, ref_column] = determine_foreign_ref(std::type_index(typeid(typename Pointer::value_type)));
columns_.push_back(fk_column_generator_.generate(id, *x, ref_table, ref_column));
if (attr.fetch() == utils::fetch_type::LAZY) {
push(id);
} else {
const auto info = table_schema_.info<typename Pointer::value_type>();
if (!info) {
return;
}
table_name_stack_.push(info.value().name);
typename Pointer::value_type obj;
matador::utils::access::process(*this, obj);
table_name_stack_.pop();
}
}
template<class Pointer>
void on_has_one(const char *id, Pointer &x, const utils::foreign_attributes &/*attr*/)
void on_has_one(const char *id, Pointer &, const utils::foreign_attributes &attr)
{
const auto [ref_table, ref_column] = determine_foreign_ref(std::type_index(typeid(typename Pointer::value_type)));
columns_.push_back(fk_column_generator_.generate(id, *x, ref_table, ref_column));
if (attr.fetch() == utils::fetch_type::LAZY) {
push(id);
} else {
const auto info = table_schema_.info<typename Pointer::value_type>();
if (!info) {
return;
}
table_name_stack_.push(info.value().name);
typename Pointer::value_type obj;
matador::utils::access::process(*this, obj);
table_name_stack_.pop();
}
}
template<class ContainerType>
void on_has_many(const char *, ContainerType &, const char *, const char *, const utils::foreign_attributes &/*attr*/) {}
void on_has_many(const char *, ContainerType &, const char *, const char *, const utils::foreign_attributes &attr)
{
if (attr.fetch() == utils::fetch_type::LAZY) {
return;
}
const auto info = table_schema_.info<typename ContainerType::value_type::value_type>();
if (!info) {
return;
}
table_name_stack_.push(info.value().name);
typename ContainerType::value_type::value_type obj;
matador::utils::access::process(*this, obj);
table_name_stack_.pop();
}
template<class ContainerType>
void on_has_many(const char *, ContainerType &, const utils::foreign_attributes &/*attr*/) {}
void on_has_many(const char *id, ContainerType &c, const utils::foreign_attributes &attr)
{
on_has_many(id, c, "", "", attr);
}
private:
std::pair<std::string, std::string> determine_foreign_ref(const std::type_index &ti);
void push(const std::string &column_name);
private:
size_t index_ = 0;
std::vector<column_definition> &columns_;
const schema &repo_;
fk_column_generator fk_column_generator_;
std::stack<std::string> table_name_stack_;
std::vector<column> &column_infos_;
const sql::schema &table_schema_;
int column_index{0};
};
template<typename V>
void column_generator::on_primary_key(const char *id, V &x, typename std::enable_if<std::is_integral<V>::value && !std::is_same<bool, V>::value>::type*)
{
on_attribute(id, x, { utils::constraints::PRIMARY_KEY });
}
template<typename Type>
void column_generator::on_attribute(const char *id, Type &x, const utils::field_attributes &attr)
{
columns_.emplace_back(id, x, attr, null_option::NOT_NULL);
}
template<typename Type>
void column_generator::on_attribute(const char *id, std::optional<Type> &x, const utils::field_attributes &attr)
{
columns_.emplace_back(id, data_type_traits<Type>::builtin_type(attr.size()), attr, null_option::NULLABLE);
}
}
#endif //QUERY_COLUMN_GENERATOR_HPP

View File

@ -1,97 +0,0 @@
#ifndef QUERY_COLUMN_NAME_GENERATOR_HPP
#define QUERY_COLUMN_NAME_GENERATOR_HPP
#include "matador/utils/access.hpp"
#include "matador/utils/field_attributes.hpp"
#include "matador/utils/foreign_attributes.hpp"
#include "matador/sql/column.hpp"
#include "matador/sql/schema.hpp"
#include <string>
#include <vector>
#include <stack>
namespace matador::sql {
class column_name_generator
{
private:
column_name_generator(std::vector<column> &column_infos, const sql::schema &ts, const std::string &table_name);
public:
~column_name_generator() = default;
template < class Type >
static std::vector<column> generate(const sql::schema &ts)
{
const auto info = ts.info<Type>();
if (!info) {
return {};
}
std::vector<column> columns;
column_name_generator gen(columns, ts, info.value().name);
Type obj;
matador::utils::access::process(gen, obj);
return std::move(columns);
}
template < class V >
void on_primary_key(const char *id, V &, typename std::enable_if<std::is_integral<V>::value && !std::is_same<bool, V>::value>::type* = 0)
{
push(id);
}
void on_primary_key(const char *id, std::string &, size_t);
void on_revision(const char *id, unsigned long long &/*rev*/);
template<typename Type>
void on_attribute(const char *id, Type &, const utils::field_attributes &/*attr*/ = utils::null_attributes)
{
push(id);
}
template<class Pointer>
void on_belongs_to(const char *id, Pointer &, const utils::foreign_attributes &/*attr*/)
{
push(id);
}
template<class Pointer>
void on_has_one(const char *id, Pointer &, const utils::foreign_attributes &/*attr*/)
{
push(id);
}
template<class ContainerType>
void on_has_many(const char *, ContainerType &, const char *, const char *, const utils::foreign_attributes &attr)
{
if (attr.fetch() == utils::fetch_type::LAZY) {
return;
}
const auto info = table_schema_.info<typename ContainerType::value_type::value_type>();
if (!info) {
return;
}
table_name_stack_.push(info.value().name);
typename ContainerType::value_type::value_type obj;
matador::utils::access::process(*this, obj);
table_name_stack_.pop();
}
template<class ContainerType>
void on_has_many(const char *id, ContainerType &c, const utils::foreign_attributes &attr)
{
on_has_many(id, c, "", "", attr);
}
private:
void push(const std::string &column_name);
private:
std::stack<std::string> table_name_stack_;
std::vector<column> &column_infos_;
const sql::schema &table_schema_;
int column_index{0};
};
}
#endif //QUERY_COLUMN_NAME_GENERATOR_HPP

View File

@ -34,13 +34,13 @@ private:
template<class Type>
query_select_intermediate query::select()
{
return select(column_name_generator::generate<Type>(schema_));
return select(column_generator::generate<Type>(schema_));
}
template<class Type>
query_select_intermediate query::select(std::initializer_list<column> columns)
{
auto cols = column_name_generator::generate<Type>(schema_);
auto cols = column_generator::generate<Type>(schema_);
cols.insert(cols.end(), columns);
return select(cols);
}

View File

@ -2,8 +2,8 @@
#define QUERY_QUERY_INTERMEDIATES_HPP
#include "matador/sql/column_definition.hpp"
#include "matador/sql/column_definition_generator.hpp"
#include "matador/sql/column_generator.hpp"
#include "matador/sql/column_name_generator.hpp"
#include "matador/sql/key_value_generator.hpp"
#include "matador/sql/key_value_pair.hpp"
#include "matador/sql/placeholder_generator.hpp"
@ -260,7 +260,7 @@ public:
// if (!schema_.exists<Type>()) {
// schema_.attach<Type>(table.name);
// }
return this->table(table, column_generator::generate<Type>(schema_));
return this->table(table, column_definition_generator::generate<Type>(schema_));
}
};
@ -282,7 +282,7 @@ public:
template<class Type>
query_into_intermediate into(const sql::table &table)
{
return into(table, column_name_generator::generate<Type>(schema_));
return into(table, column_generator::generate<Type>(schema_));
}
};

View File

@ -1,7 +1,7 @@
#ifndef QUERY_SCHEMA_HPP
#define QUERY_SCHEMA_HPP
#include "matador/sql/column_generator.hpp"
#include "matador/sql/column_definition_generator.hpp"
#include "matador/sql/table_definition.hpp"
#include <optional>
@ -38,7 +38,7 @@ public:
template<typename Type>
const table_info& attach(const std::string &table_name)
{
return attach(std::type_index(typeid(Type)), table_info{table_name, table_definition{column_generator::generate<Type>(*this)}});
return attach(std::type_index(typeid(Type)), table_info{table_name, table_definition{column_definition_generator::generate<Type>(*this)}});
}
const table_info& attach(std::type_index ti, const table_info& table);

View File

@ -12,8 +12,8 @@ set(SQL_SOURCES
sql/session.cpp
sql/backend_provider.cpp
sql/query_result_impl.cpp
sql/column_definition_generator.cpp
sql/column_generator.cpp
sql/column_name_generator.cpp
sql/key_value_generator.cpp
sql/fk_value_extractor.cpp
sql/schema.cpp
@ -57,8 +57,8 @@ set(SQL_HEADER
../include/matador/sql/session.hpp
../include/matador/sql/backend_provider.hpp
../include/matador/sql/query_result_impl.hpp
../include/matador/sql/column_definition_generator.hpp
../include/matador/sql/column_generator.hpp
../include/matador/sql/column_name_generator.hpp
../include/matador/sql/value_extractor.hpp
../include/matador/sql/any_type.hpp
../include/matador/sql/key_value_generator.hpp

View File

@ -7,4 +7,38 @@ column operator ""_col(const char *name, size_t len)
return {{name, len}};
}
column::column(const char *name) : name(name) {}
column::column(std::string name) : name(std::move(name)) {}
column::column(sql_function_t func, std::string name) : name(std::move(name)), function_(func) {}
column::column(std::string table_name, std::string name, std::string as)
: table(std::move(table_name))
, name(std::move(name))
, alias(std::move(as)) {}
column::column(std::string table_name, const char *name, std::string as)
: table(std::move(table_name))
, name(name)
, alias(std::move(as)) {}
bool column::equals(const column &x) const
{
return table == x.table &&
name == x.name &&
alias == x.alias &&
function_ == x.function_;
}
column &column::as(std::string a)
{
alias = std::move(a);
return *this;
}
bool column::is_function() const
{
return function_ != sql_function_t::NONE;
}
}

View File

@ -0,0 +1,31 @@
#include "matador/sql/column_definition_generator.hpp"
#include "matador/sql/schema.hpp"
namespace matador::sql {
column_definition_generator::column_definition_generator(std::vector<column_definition> &columns, const schema &repo)
: columns_(columns)
, repo_(repo)
{}
void column_definition_generator::on_primary_key(const char *id, std::string &pk, size_t size)
{
on_attribute(id, pk, { size, utils::constraints::PRIMARY_KEY });
}
void column_definition_generator::on_revision(const char *id, unsigned long long int &x)
{
on_attribute(id, x);
}
std::pair<std::string, std::string> column_definition_generator::determine_foreign_ref(const std::type_index &ti)
{
return repo_.reference(ti);
}
void fk_column_generator::on_primary_key(const char *, std::string &, size_t size)
{
type_ = data_type_traits<std::string>::builtin_type(size);
}
}

View File

@ -1,31 +1,31 @@
#include "matador/sql/column_generator.hpp"
#include "matador/sql/schema.hpp"
namespace matador::sql {
column_generator::column_generator(std::vector<column_definition> &columns, const schema &repo)
: columns_(columns)
, repo_(repo)
{}
void column_generator::on_primary_key(const char *id, std::string &pk, size_t size)
column_generator::column_generator(std::vector<column> &column_infos,
const sql::schema &ts,
const std::string &table_name)
: column_infos_(column_infos)
, table_schema_(ts)
{
on_attribute(id, pk, { size, utils::constraints::PRIMARY_KEY });
table_name_stack_.push(table_name);
}
void column_generator::on_revision(const char *id, unsigned long long int &x)
void column_generator::on_primary_key(const char *id, std::string &, size_t)
{
on_attribute(id, x);
push(id);
}
std::pair<std::string, std::string> column_generator::determine_foreign_ref(const std::type_index &ti)
void column_generator::on_revision(const char *id, unsigned long long int &)
{
return repo_.reference(ti);
push(id);
}
void fk_column_generator::on_primary_key(const char *, std::string &, size_t size)
void column_generator::push(const std::string &column_name)
{
type_ = data_type_traits<std::string>::builtin_type(size);
char str[4];
snprintf(str, 4, "c%02d", ++column_index);
column_infos_.emplace_back(table_name_stack_.top(), column_name, str);
}
}

View File

@ -1,31 +0,0 @@
#include "matador/sql/column_name_generator.hpp"
namespace matador::sql {
column_name_generator::column_name_generator(std::vector<column> &column_infos,
const sql::schema &ts,
const std::string &table_name)
: column_infos_(column_infos)
, table_schema_(ts)
{
table_name_stack_.push(table_name);
}
void column_name_generator::on_primary_key(const char *id, std::string &, size_t)
{
push(id);
}
void column_name_generator::on_revision(const char *id, unsigned long long int &)
{
push(id);
}
void column_name_generator::push(const std::string &column_name)
{
char str[4];
snprintf(str, 4, "c%02d", ++column_index);
column_infos_.emplace_back(table_name_stack_.top(), column_name, str);
}
}

View File

@ -1,5 +1,5 @@
#include "matador/sql/query_builder.hpp"
#include "matador/sql/column_name_generator.hpp"
#include "matador/sql/column_generator.hpp"
#include "matador/sql/column.hpp"
#include "matador/sql/dialect.hpp"

View File

@ -20,8 +20,8 @@ add_executable(tests
models/product.hpp
models/order.hpp
models/order_details.h
ColumnDefinitionGeneratorTest.cpp
ColumnGeneratorTest.cpp
ColumnNameGeneratorTest.cpp
ValueGeneratorTest.cpp
models/category.hpp
models/supplier.hpp

View File

@ -0,0 +1,56 @@
#include <catch2/catch_test_macros.hpp>
#include "matador/sql/column_definition_generator.hpp"
#include "matador/sql/schema.hpp"
#include "models/product.hpp"
#include "models/optional.hpp"
using namespace matador::sql;
using namespace matador::utils;
TEST_CASE("Generate columns from object", "[column generator]") {
schema repo("main");
auto columns = column_definition_generator::generate<matador::test::product>(repo);
const std::vector<column_definition> expected_columns = {
column_definition{"product_name", data_type_t::type_varchar, constraints::PRIMARY_KEY, null_option::NOT_NULL },
column_definition{"supplier_id", data_type_t::type_unsigned_long, constraints::FOREIGN_KEY, null_option::NOT_NULL },
column_definition{"category_id", data_type_t::type_unsigned_long, constraints::FOREIGN_KEY, null_option::NOT_NULL },
column_definition{"quantity_per_unit", data_type_t::type_varchar, null_attributes, null_option::NOT_NULL },
column_definition{"unit_price", data_type_t::type_unsigned_int, null_attributes, null_option::NOT_NULL },
column_definition{"units_in_stock", data_type_t::type_unsigned_int, null_attributes, null_option::NOT_NULL },
column_definition{"units_in_order", data_type_t::type_unsigned_int, null_attributes, null_option::NOT_NULL },
column_definition{"reorder_level", data_type_t::type_unsigned_int, null_attributes, null_option::NOT_NULL },
column_definition{"discontinued", data_type_t::type_bool, null_attributes, null_option::NOT_NULL }
};
REQUIRE(!columns.empty());
REQUIRE(columns.size() == expected_columns.size());
for (size_t i = 0; i != expected_columns.size(); ++i) {
REQUIRE(expected_columns[i].name() == columns[i].name());
REQUIRE(expected_columns[i].attributes().options() == columns[i].attributes().options() );
REQUIRE(expected_columns[i].type() == columns[i].type() );
}
}
TEST_CASE("Generate columns from object with nullable columns", "[column generator]") {
schema repo("main");
auto columns = column_definition_generator::generate<matador::test::optional>(repo);
const std::vector<column_definition> expected_columns = {
column_definition{"id", data_type_t::type_unsigned_long, constraints::PRIMARY_KEY, null_option::NOT_NULL },
column_definition{"name", data_type_t::type_varchar, null_attributes, null_option::NOT_NULL },
column_definition{"age", data_type_t::type_unsigned_int, null_attributes, null_option::NOT_NULL }
};
REQUIRE(!columns.empty());
REQUIRE(columns.size() == expected_columns.size());
for (size_t i = 0; i != expected_columns.size(); ++i) {
REQUIRE(expected_columns[i].name() == columns[i].name());
REQUIRE(expected_columns[i].attributes().options() == columns[i].attributes().options() );
REQUIRE(expected_columns[i].type() == columns[i].type() );
}
}

View File

@ -3,54 +3,96 @@
#include "matador/sql/column_generator.hpp"
#include "matador/sql/schema.hpp"
#include "models/order.hpp"
#include "models/product.hpp"
#include "models/optional.hpp"
#include "models/book.hpp"
#include "models/author.hpp"
using namespace matador::sql;
using namespace matador::utils;
TEST_CASE("Generate columns from object", "[column generator]") {
schema repo("main");
TEST_CASE("Generate columns from object", "[column][generator]") {
using namespace matador::test;
schema s("main");
s.attach<product>("product");
auto columns = column_generator::generate<matador::test::product>(repo);
auto columns = column_generator::generate<product>(s);
const std::vector<column_definition> expected_columns = {
column_definition{"product_name", data_type_t::type_varchar, constraints::PRIMARY_KEY, null_option::NOT_NULL },
column_definition{"supplier_id", data_type_t::type_unsigned_long, constraints::FOREIGN_KEY, null_option::NOT_NULL },
column_definition{"category_id", data_type_t::type_unsigned_long, constraints::FOREIGN_KEY, null_option::NOT_NULL },
column_definition{"quantity_per_unit", data_type_t::type_varchar, null_attributes, null_option::NOT_NULL },
column_definition{"unit_price", data_type_t::type_unsigned_int, null_attributes, null_option::NOT_NULL },
column_definition{"units_in_stock", data_type_t::type_unsigned_int, null_attributes, null_option::NOT_NULL },
column_definition{"units_in_order", data_type_t::type_unsigned_int, null_attributes, null_option::NOT_NULL },
column_definition{"reorder_level", data_type_t::type_unsigned_int, null_attributes, null_option::NOT_NULL },
column_definition{"discontinued", data_type_t::type_bool, null_attributes, null_option::NOT_NULL }
const std::vector<std::string> expected_columns = {
"product_name",
"supplier_id",
"category_id",
"quantity_per_unit",
"unit_price",
"units_in_stock",
"units_in_order",
"reorder_level",
"discontinued"
};
REQUIRE(!columns.empty());
REQUIRE(columns.size() == expected_columns.size());
for (size_t i = 0; i != expected_columns.size(); ++i) {
REQUIRE(expected_columns[i].name() == columns[i].name());
REQUIRE(expected_columns[i].attributes().options() == columns[i].attributes().options() );
REQUIRE(expected_columns[i].type() == columns[i].type() );
REQUIRE(expected_columns[i] == columns[i].name);
}
}
TEST_CASE("Generate columns from object with nullable columns", "[column generator]") {
schema repo("main");
TEST_CASE("Generate columns for object with has many relation", "[column][generator][relation]") {
using namespace matador::test;
schema s("main");
s.attach<product>("product");
s.attach<order_details>("order_details");
s.attach<order>("order");
auto columns = column_generator::generate<matador::test::optional>(repo);
auto columns = column_generator::generate<order>(s);
const std::vector<column_definition> expected_columns = {
column_definition{"id", data_type_t::type_unsigned_long, constraints::PRIMARY_KEY, null_option::NOT_NULL },
column_definition{"name", data_type_t::type_varchar, null_attributes, null_option::NOT_NULL },
column_definition{"age", data_type_t::type_unsigned_int, null_attributes, null_option::NOT_NULL }
const std::vector<column> expected_columns = {
{ "order", "order_id", "c01" },
{ "order", "order_date", "c02" },
{ "order", "required_date", "c03" },
{ "order", "shipped_date", "c04" },
{ "order", "ship_via", "c05" },
{ "order", "freight", "c06" },
{ "order", "ship_name", "c07" },
{ "order", "ship_address", "c08" },
{ "order", "ship_city", "c09" },
{ "order", "ship_region", "c10" },
{ "order", "ship_postal_code", "c11" },
{ "order", "ship_country", "c12" },
{ "order_details", "order_details_id", "c13" },
{ "order_details", "order_id", "c14" },
{ "order_details", "product_id", "c15" }
};
REQUIRE(!columns.empty());
REQUIRE(columns.size() == expected_columns.size());
for (size_t i = 0; i != expected_columns.size(); ++i) {
REQUIRE(expected_columns[i].name() == columns[i].name());
REQUIRE(expected_columns[i].attributes().options() == columns[i].attributes().options() );
REQUIRE(expected_columns[i].type() == columns[i].type() );
REQUIRE(expected_columns[i].equals(columns[i]));
}
}
TEST_CASE("Generate columns for object with eager foreign key relation", "[column][generator][eager]") {
using namespace matador::test;
schema s("main");
s.attach<book>("books");
s.attach<author>("authors");
const std::vector<column> expected_columns {
{ "books", "id", "c01" },
{ "books", "title", "c02" },
{ "authors", "id", "c03" },
{ "authors", "first_name", "c04" },
{ "authors", "last_name", "c05" },
{ "authors", "date_of_birth", "c06" },
{ "authors", "year_of_birth", "c07" },
{ "authors", "distinguished", "c08" },
{ "books", "published_in", "c09" }
};
auto columns = column_generator::generate<book>(s);
REQUIRE(!columns.empty());
REQUIRE(columns.size() == expected_columns.size());
for (size_t i = 0; i != expected_columns.size(); ++i) {
REQUIRE(expected_columns[i].equals(columns[i]));
}
}

View File

@ -1,68 +0,0 @@
#include <catch2/catch_test_macros.hpp>
#include "matador/sql/column_name_generator.hpp"
#include "matador/sql/schema.hpp"
#include "models/order.hpp"
#include "models/product.hpp"
using namespace matador::sql;
TEST_CASE("Generate column names from object", "[column name generator]") {
schema s("main");
s.attach<matador::test::product>("product");
auto columns = column_name_generator::generate<matador::test::product>(s);
const std::vector<std::string> expected_columns = {
"product_name",
"supplier_id",
"category_id",
"quantity_per_unit",
"unit_price",
"units_in_stock",
"units_in_order",
"reorder_level",
"discontinued"
};
REQUIRE(!columns.empty());
REQUIRE(columns.size() == expected_columns.size());
for (size_t i = 0; i != expected_columns.size(); ++i) {
REQUIRE(expected_columns[i] == columns[i].name);
}
}
TEST_CASE("Generate column names for object with has many relation", "[column][relation]") {
schema s("main");
s.attach<matador::test::product>("product");
s.attach<matador::test::order_details>("order_details");
s.attach<matador::test::order>("order");
auto columns = column_name_generator::generate<matador::test::order>(s);
const std::vector<std::string> expected_columns = {
"order_id",
"order_date",
"required_date",
"shipped_date",
"ship_via",
"freight",
"ship_name",
"ship_address",
"ship_city",
"ship_region",
"ship_postal_code",
"ship_country",
"order_details_id",
"order_id",
"product_id",
};
REQUIRE(!columns.empty());
REQUIRE(columns.size() == expected_columns.size());
for (size_t i = 0; i != expected_columns.size(); ++i) {
REQUIRE(expected_columns[i] == columns[i].name);
}
}

View File

@ -25,7 +25,7 @@ struct book
namespace field = matador::utils::access;
field::primary_key(op, "id", id);
field::attribute(op, "title", title, 511);
field::has_one(op, "author_id", book_author, matador::utils::default_foreign_attributes);
field::has_one(op, "author_id", book_author, utils::fetch_type::EAGER);
field::attribute(op, "published_in", published_in);
}
};