column generator progress
This commit is contained in:
parent
1c5b2b21b0
commit
0d08ad4179
|
|
@ -248,7 +248,7 @@ utils::result<object::object_ptr<Type>, utils::error> session::update( const obj
|
||||||
|
|
||||||
const auto col = sql::column(info.value().get().definition().primary_key()->name());
|
const auto col = sql::column(info.value().get().definition().primary_key()->name());
|
||||||
auto res = matador::query::query::update(info->get().name())
|
auto res = matador::query::query::update(info->get().name())
|
||||||
.set(generator::placeholders<Type>())
|
.set(generator::column_value_pairs<Type>())
|
||||||
.where(col == _)
|
.where(col == _)
|
||||||
.prepare(*this);
|
.prepare(*this);
|
||||||
if (!res) {
|
if (!res) {
|
||||||
|
|
|
||||||
|
|
@ -22,13 +22,18 @@ enum class column_generator_options {
|
||||||
ForceLazy = 1 << 1
|
ForceLazy = 1 << 1
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename EnumType>
|
// template<typename EnumType>
|
||||||
class enum_flags {
|
// class enum_flags {
|
||||||
public:
|
// public:
|
||||||
explicit enum_flags(EnumType value) : value_(value) {}
|
// explicit enum_flags(EnumType value) : value_(value) {}
|
||||||
private:
|
//
|
||||||
EnumType value_;
|
// operator EnumType() const { return value_; }
|
||||||
};
|
//
|
||||||
|
// enum_flags operator|=(EnumType other) { value_ |= other; return *this; }
|
||||||
|
// enum_flags operator&=(EnumType other) { value_ |= other; return *this; })
|
||||||
|
// private:
|
||||||
|
// EnumType value_;
|
||||||
|
// };
|
||||||
|
|
||||||
inline column_generator_options operator|(column_generator_options a, column_generator_options b) { return static_cast<column_generator_options>(static_cast<unsigned int>(a) | static_cast<unsigned int>(b)); }
|
inline column_generator_options operator|(column_generator_options a, column_generator_options b) { return static_cast<column_generator_options>(static_cast<unsigned int>(a) | static_cast<unsigned int>(b)); }
|
||||||
inline column_generator_options operator&(column_generator_options a, column_generator_options b) { return static_cast<column_generator_options>(static_cast<unsigned int>(a) & static_cast<unsigned int>(b)); }
|
inline column_generator_options operator&(column_generator_options a, column_generator_options b) { return static_cast<column_generator_options>(static_cast<unsigned int>(a) & static_cast<unsigned int>(b)); }
|
||||||
|
|
@ -187,7 +192,7 @@ public:
|
||||||
result_.emplace_back(utils::_);
|
result_.emplace_back(utils::_);
|
||||||
}
|
}
|
||||||
template<class ContainerType>
|
template<class ContainerType>
|
||||||
static void on_has_many(const char * /*id*/, ContainerType &, const char *, const utils::foreign_attributes &attr) {}
|
static void on_has_many(const char * /*id*/, ContainerType &, const char *, const utils::foreign_attributes &/*attr*/) {}
|
||||||
template<class ContainerType>
|
template<class ContainerType>
|
||||||
static void on_has_many_to_many(const char *, ContainerType &, const char *, const char *, const utils::foreign_attributes &/*attr*/) {}
|
static void on_has_many_to_many(const char *, ContainerType &, const char *, const char *, const utils::foreign_attributes &/*attr*/) {}
|
||||||
template<class ContainerType>
|
template<class ContainerType>
|
||||||
|
|
@ -196,53 +201,74 @@ public:
|
||||||
private:
|
private:
|
||||||
std::vector<utils::placeholder> result_;
|
std::vector<utils::placeholder> result_;
|
||||||
};
|
};
|
||||||
|
enum class column_value_generator_options {
|
||||||
|
None = 0,
|
||||||
|
ValuesAsPlaceHolder = 1 << 0
|
||||||
|
};
|
||||||
|
|
||||||
|
inline column_value_generator_options operator|(column_value_generator_options a, column_value_generator_options b) { return static_cast<column_value_generator_options>(static_cast<unsigned int>(a) | static_cast<unsigned int>(b)); }
|
||||||
|
inline column_value_generator_options operator&(column_value_generator_options a, column_value_generator_options b) { return static_cast<column_value_generator_options>(static_cast<unsigned int>(a) & static_cast<unsigned int>(b)); }
|
||||||
|
inline column_value_generator_options& operator|= (column_value_generator_options& a, column_value_generator_options b) { return reinterpret_cast<column_value_generator_options&>(reinterpret_cast<int&>(a) |= static_cast<int>(b)); }
|
||||||
|
inline column_value_generator_options& operator&= (column_value_generator_options& a, column_value_generator_options b) { return reinterpret_cast<column_value_generator_options&>(reinterpret_cast<int&>(a) &= static_cast<int>(b)); }
|
||||||
|
|
||||||
|
inline bool is_column_value_generator_option_set(const column_value_generator_options source, const column_value_generator_options needle) { return static_cast<int>(source & needle) > 0; }
|
||||||
|
|
||||||
class column_value_generator final {
|
class column_value_generator final {
|
||||||
public:
|
public:
|
||||||
template< class Type >
|
explicit column_value_generator(column_value_generator_options options = column_value_generator_options::None);
|
||||||
std::vector<internal::column_value_pair> generate() {
|
template< class Type >
|
||||||
Type obj;
|
std::vector<internal::column_value_pair> generate() {
|
||||||
return generate(obj);
|
Type obj;
|
||||||
}
|
return generate(obj);
|
||||||
|
}
|
||||||
|
|
||||||
template< class Type >
|
template< class Type >
|
||||||
std::vector<internal::column_value_pair> generate(const Type &obj) {
|
std::vector<internal::column_value_pair> generate(const Type &obj) {
|
||||||
result_.clear();
|
result_.clear();
|
||||||
access::process(*this, obj);
|
access::process(*this, obj);
|
||||||
|
|
||||||
return result_;
|
return result_;
|
||||||
}
|
}
|
||||||
|
|
||||||
template < class V >
|
template < class V >
|
||||||
void on_primary_key(const char *id, V &x, const utils::primary_key_attribute& /*attr*/ = utils::default_pk_attributes) {
|
void on_primary_key(const char *id, V &x, const utils::primary_key_attribute& /*attr*/ = utils::default_pk_attributes) {
|
||||||
result_.emplace_back(id, x);
|
push_back(id, x);
|
||||||
}
|
}
|
||||||
void on_revision(const char *id, uint64_t &/*rev*/);
|
void on_revision(const char *id, uint64_t &/*rev*/);
|
||||||
|
|
||||||
template<typename Type>
|
template<typename Type>
|
||||||
void on_attribute(const char *id, Type &x, const utils::field_attributes &/*attr*/ = utils::null_attributes) {
|
void on_attribute(const char *id, Type &x, const utils::field_attributes &/*attr*/ = utils::null_attributes) {
|
||||||
result_.emplace_back(id, x);
|
push_back(id, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Type, template < class ... > class Pointer>
|
template<class Type, template < class ... > class Pointer>
|
||||||
void on_belongs_to(const char *id, Pointer<Type> &x, const utils::foreign_attributes &/*attr*/) {
|
void on_belongs_to(const char *id, Pointer<Type> &x, const utils::foreign_attributes &/*attr*/) {
|
||||||
result_.emplace_back(id, fk_value_extractor_.extract(*x));
|
push_back(id, fk_value_extractor_.extract(*x));
|
||||||
|
}
|
||||||
|
template<class Type, template < class ... > class Pointer>
|
||||||
|
void on_has_one(const char *id, Pointer<Type> &x, const utils::foreign_attributes &/*attr*/) {
|
||||||
|
push_back(id, fk_value_extractor_.extract(*x));
|
||||||
|
}
|
||||||
|
template<class ContainerType>
|
||||||
|
static void on_has_many(const char * /*id*/, ContainerType &, const char *, const utils::foreign_attributes &/*attr*/) {}
|
||||||
|
template<class ContainerType>
|
||||||
|
static void on_has_many_to_many(const char *, ContainerType &, const char *, const char *, const utils::foreign_attributes &/*attr*/) {}
|
||||||
|
template<class ContainerType>
|
||||||
|
static void on_has_many_to_many(const char *, ContainerType &, const utils::foreign_attributes &/*attr*/) {}
|
||||||
|
|
||||||
|
template<typename Type>
|
||||||
|
void push_back(const char* id, const Type& value) {
|
||||||
|
if (is_column_value_generator_option_set(options_, column_value_generator_options::ValuesAsPlaceHolder)) {
|
||||||
|
result_.emplace_back(id, utils::_);
|
||||||
|
} else {
|
||||||
|
result_.emplace_back(id, value);
|
||||||
}
|
}
|
||||||
template<class Type, template < class ... > class Pointer>
|
}
|
||||||
void on_has_one(const char *id, Pointer<Type> &x, const utils::foreign_attributes &/*attr*/) {
|
|
||||||
result_.emplace_back(id, fk_value_extractor_.extract(*x));
|
|
||||||
}
|
|
||||||
template<class ContainerType>
|
|
||||||
static void on_has_many(const char * /*id*/, ContainerType &, const char *, const utils::foreign_attributes &attr) {}
|
|
||||||
template<class ContainerType>
|
|
||||||
static void on_has_many_to_many(const char *, ContainerType &, const char *, const char *, const utils::foreign_attributes &/*attr*/) {}
|
|
||||||
template<class ContainerType>
|
|
||||||
static void on_has_many_to_many(const char *, ContainerType &, const utils::foreign_attributes &/*attr*/) {}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
detail::fk_value_extractor fk_value_extractor_{};
|
detail::fk_value_extractor fk_value_extractor_{};
|
||||||
std::vector<internal::column_value_pair> result_;
|
std::vector<internal::column_value_pair> result_;
|
||||||
|
column_value_generator_options options_{column_value_generator_options::None};
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Type>
|
template<typename Type>
|
||||||
|
|
@ -258,11 +284,17 @@ std::vector<utils::placeholder> placeholders(const Type &obj) {
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Type>
|
template<typename Type>
|
||||||
std::vector<internal::column_value_pair> column_value_pairs(const Type &obj) {
|
std::vector<internal::column_value_pair> column_value_pairs(const Type &obj, const column_value_generator_options options = column_value_generator_options::None) {
|
||||||
column_value_generator generator;
|
column_value_generator generator(options);
|
||||||
return generator.generate(obj);
|
return generator.generate(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename Type>
|
||||||
|
std::vector<internal::column_value_pair> column_value_pairs() {
|
||||||
|
Type obj;
|
||||||
|
return column_value_pairs(obj, column_value_generator_options::ValuesAsPlaceHolder);
|
||||||
|
}
|
||||||
|
|
||||||
template<typename Type>
|
template<typename Type>
|
||||||
std::vector<sql::column> columns(const object::repository &repo,
|
std::vector<sql::column> columns(const object::repository &repo,
|
||||||
const std::string &table_name = "",
|
const std::string &table_name = "",
|
||||||
|
|
|
||||||
|
|
@ -19,11 +19,6 @@ public:
|
||||||
executable_query values(std::vector<utils::placeholder> &&values);
|
executable_query values(std::vector<utils::placeholder> &&values);
|
||||||
executable_query values(std::vector<utils::database_type> &&values);
|
executable_query values(std::vector<utils::database_type> &&values);
|
||||||
template<class Type>
|
template<class Type>
|
||||||
executable_query values() {
|
|
||||||
Type obj;
|
|
||||||
return values(obj);
|
|
||||||
}
|
|
||||||
template<class Type>
|
|
||||||
executable_query values(const Type &obj) {
|
executable_query values(const Type &obj) {
|
||||||
return values(value_extractor::extract(obj));
|
return values(value_extractor::extract(obj));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,11 +18,6 @@ public:
|
||||||
query_set_intermediate set(std::initializer_list<internal::column_value_pair> columns);
|
query_set_intermediate set(std::initializer_list<internal::column_value_pair> columns);
|
||||||
query_set_intermediate set(std::vector<internal::column_value_pair> &&columns);
|
query_set_intermediate set(std::vector<internal::column_value_pair> &&columns);
|
||||||
template<class Type>
|
template<class Type>
|
||||||
query_set_intermediate set() {
|
|
||||||
Type obj;
|
|
||||||
return set(obj);
|
|
||||||
}
|
|
||||||
template<class Type>
|
|
||||||
query_set_intermediate set(const Type &obj) {
|
query_set_intermediate set(const Type &obj) {
|
||||||
return set(key_value_generator::generate(obj));
|
return set(key_value_generator::generate(obj));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,112 @@
|
||||||
|
#ifndef MATADOR_GENERATOR_HPP
|
||||||
|
#define MATADOR_GENERATOR_HPP
|
||||||
|
|
||||||
|
#include <matador/object/repository.hpp>
|
||||||
|
|
||||||
|
#include <matador/utils/placeholder.hpp>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace matador::sql::generator {
|
||||||
|
template < class Type >
|
||||||
|
static std::vector<utils::placeholder> placeholder(const object::repository &repo);
|
||||||
|
template < class Type >
|
||||||
|
static std::vector<utils::placeholder> columns(const object::repository &repo);
|
||||||
|
template < class Type >
|
||||||
|
static std::vector<utils::placeholder> key_values(const object::repository &repo);
|
||||||
|
|
||||||
|
class placeholder_generator {
|
||||||
|
public:
|
||||||
|
|
||||||
|
template < class Type >
|
||||||
|
static std::vector<utils::placeholder> generate(const object::repository &repo, const bool force_lazy = false) {
|
||||||
|
const auto info = repo.info<Type>();
|
||||||
|
if (!info) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
std::vector<utils::placeholder> columns;
|
||||||
|
placeholder_generator gen(columns, repo, info.value().get().name(), force_lazy);
|
||||||
|
Type obj;
|
||||||
|
access::process(gen, obj);
|
||||||
|
return columns;
|
||||||
|
}
|
||||||
|
|
||||||
|
template < class Type >
|
||||||
|
static std::vector<utils::placeholder> generate_has_many_to_many(const object::repository &scm, const bool force_lazy = false) {
|
||||||
|
const auto info = scm.info<Type>();
|
||||||
|
if (!info) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
std::vector<utils::placeholder> columns;
|
||||||
|
placeholder_generator gen(columns, scm, info.value().get().name(), force_lazy);
|
||||||
|
Type obj;
|
||||||
|
access::process(gen, obj);
|
||||||
|
return columns;
|
||||||
|
}
|
||||||
|
|
||||||
|
template < class V >
|
||||||
|
void on_primary_key(const char *id, V &, const utils::primary_key_attribute& /*attr*/ = utils::default_pk_attributes) {
|
||||||
|
if (has_many_to_many_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
push(id);
|
||||||
|
}
|
||||||
|
void on_revision(const char *id, uint64_t &/*rev*/);
|
||||||
|
|
||||||
|
template<typename Type>
|
||||||
|
void on_attribute(const char *id, Type &, const utils::field_attributes &/*attr*/ = utils::null_attributes) {
|
||||||
|
if (has_many_to_many_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
push(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Pointer>
|
||||||
|
void on_belongs_to(const char *id, Pointer &x, const utils::foreign_attributes &attr) {
|
||||||
|
on_foreign_key(id, x, attr);
|
||||||
|
}
|
||||||
|
template<class Pointer>
|
||||||
|
void on_has_one(const char *id, Pointer &x, const utils::foreign_attributes &attr) {
|
||||||
|
on_foreign_key(id, x, attr);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ContainerType>
|
||||||
|
void on_has_many(const char * /*id*/, ContainerType &, const char *, const utils::foreign_attributes &attr) {
|
||||||
|
if (has_many_to_many_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (attr.fetch() == utils::fetch_type::LAZY || force_lazy_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto info = table_schema_.info<typename ContainerType::value_type::value_type>();
|
||||||
|
if (!info) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (seen_tables.count(info->get().name()) == 0) {
|
||||||
|
auto it = seen_tables.insert(info->get().name()).first;
|
||||||
|
table_name_stack_.push(info.value().get().name());
|
||||||
|
typename ContainerType::value_type::value_type obj;
|
||||||
|
access::process(*this, obj);
|
||||||
|
table_name_stack_.pop();
|
||||||
|
seen_tables.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ContainerType>
|
||||||
|
void on_has_many_to_many(const char * /*id*/, ContainerType & /*cont*/, const char *join_column, const char *inverse_join_column, const utils::foreign_attributes &/*attr*/) {
|
||||||
|
if (!has_many_to_many_) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
push(join_column);
|
||||||
|
push(inverse_join_column);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class ContainerType>
|
||||||
|
static void on_has_many_to_many(const char * /*id*/, ContainerType & /*cont*/, const utils::foreign_attributes &/*attr*/) {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif //MATADOR_GENERATOR_HPP
|
||||||
|
|
@ -30,7 +30,10 @@ void placeholder_generator::on_revision(const char* /*id*/, uint64_t&) {
|
||||||
result_.emplace_back(utils::_);
|
result_.emplace_back(utils::_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
column_value_generator::column_value_generator(column_value_generator_options options)
|
||||||
|
: options_(options) {}
|
||||||
|
|
||||||
void column_value_generator::on_revision(const char* id, uint64_t& x) {
|
void column_value_generator::on_revision(const char* id, uint64_t& x) {
|
||||||
result_.emplace_back(id, x);
|
push_back(id, x);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -393,7 +393,7 @@ TEST_CASE_METHOD(QueryFixture, "Test primary key prepared", "[query][primary key
|
||||||
|
|
||||||
auto stmt = query::insert()
|
auto stmt = query::insert()
|
||||||
.into("pk", generator::columns<pk>(repo))
|
.into("pk", generator::columns<pk>(repo))
|
||||||
.values<pk>()
|
.values(generator::placeholders<pk>())
|
||||||
.prepare(db);
|
.prepare(db);
|
||||||
REQUIRE(stmt);
|
REQUIRE(stmt);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ TEST_CASE_METHOD(QueryFixture, "Test insert statement", "[query][statement][inse
|
||||||
|
|
||||||
stmt = query::insert()
|
stmt = query::insert()
|
||||||
.into<person>("person", repo)
|
.into<person>("person", repo)
|
||||||
.values<person>()
|
.values(generator::placeholders<person>())
|
||||||
.prepare(db);
|
.prepare(db);
|
||||||
REQUIRE(stmt);
|
REQUIRE(stmt);
|
||||||
|
|
||||||
|
|
@ -102,7 +102,7 @@ TEST_CASE_METHOD(QueryFixture, "Test update statement", "[query][statement][upda
|
||||||
|
|
||||||
stmt = query::insert()
|
stmt = query::insert()
|
||||||
.into<person>("person", repo)
|
.into<person>("person", repo)
|
||||||
.values<person>()
|
.values(generator::placeholders<person>())
|
||||||
.prepare(db);
|
.prepare(db);
|
||||||
REQUIRE(stmt);
|
REQUIRE(stmt);
|
||||||
|
|
||||||
|
|
@ -125,7 +125,7 @@ TEST_CASE_METHOD(QueryFixture, "Test update statement", "[query][statement][upda
|
||||||
george.age = 36;
|
george.age = 36;
|
||||||
george.image = {5,6,7,8};
|
george.image = {5,6,7,8};
|
||||||
stmt = query::update("person")
|
stmt = query::update("person")
|
||||||
.set<person>()
|
.set(generator::column_value_pairs<person>())
|
||||||
.where("id"_col == _)
|
.where("id"_col == _)
|
||||||
.prepare(db);
|
.prepare(db);
|
||||||
REQUIRE(stmt);
|
REQUIRE(stmt);
|
||||||
|
|
@ -166,7 +166,7 @@ TEST_CASE_METHOD(QueryFixture, "Test delete statement", "[query][statement][dele
|
||||||
|
|
||||||
stmt = query::insert()
|
stmt = query::insert()
|
||||||
.into<person>("person", repo)
|
.into<person>("person", repo)
|
||||||
.values<person>()
|
.values(generator::placeholders<person>())
|
||||||
.prepare(db);
|
.prepare(db);
|
||||||
REQUIRE(stmt);
|
REQUIRE(stmt);
|
||||||
|
|
||||||
|
|
@ -253,7 +253,7 @@ TEST_CASE_METHOD(QueryFixture, "Test reuse prepared statement", "[query][stateme
|
||||||
|
|
||||||
stmt = query::insert()
|
stmt = query::insert()
|
||||||
.into<person>("person", repo)
|
.into<person>("person", repo)
|
||||||
.values<person>()
|
.values(generator::placeholders<person>())
|
||||||
.prepare(db);
|
.prepare(db);
|
||||||
REQUIRE(stmt);
|
REQUIRE(stmt);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ TEST_CASE_METHOD(TypeTraitsTestFixture, "Special handling of attributes with typ
|
||||||
|
|
||||||
auto stmt = query::insert()
|
auto stmt = query::insert()
|
||||||
.into("location", generator::columns<location>(repo))
|
.into("location", generator::columns<location>(repo))
|
||||||
.values<location>()
|
.values(generator::placeholders<location>())
|
||||||
.prepare(db);
|
.prepare(db);
|
||||||
REQUIRE(stmt);
|
REQUIRE(stmt);
|
||||||
auto res = stmt->bind(loc)
|
auto res = stmt->bind(loc)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue