Compare commits

..

No commits in common. "f38be4c6d987d1aceeca87fea193c349f713e96b" and "746fd9e8d25b703956f388bc85c7ed0e5ec59849" have entirely different histories.

19 changed files with 154 additions and 228 deletions

View File

@ -2,32 +2,24 @@
#define QUERY_INTO_INTERMEDIATE_HPP #define QUERY_INTO_INTERMEDIATE_HPP
#include "matador/query/intermediates/executable_query.hpp" #include "matador/query/intermediates/executable_query.hpp"
#include "matador/query/intermediates/fetchable_query.hpp"
#include "matador/query/value_extractor.hpp" #include "matador/query/value_extractor.hpp"
#include "matador/utils/placeholder.hpp" #include "matador/utils/placeholder.hpp"
namespace matador::query { namespace matador::query {
class table_column;
class query_values_intermediate : public executable_query { class query_into_intermediate : public query_intermediate
public: {
using executable_query::executable_query;
fetchable_query returning(const table_column &col);
};
class query_into_intermediate : public query_intermediate {
public: public:
using query_intermediate::query_intermediate; using query_intermediate::query_intermediate;
query_values_intermediate values(std::initializer_list<std::variant<utils::placeholder, utils::database_type>> values); executable_query values(std::initializer_list<std::variant<utils::placeholder, utils::database_type>> values);
query_values_intermediate values(std::vector<std::variant<utils::placeholder, utils::database_type>> &&values); executable_query values(std::vector<std::variant<utils::placeholder, utils::database_type>> &&values);
query_values_intermediate values(std::vector<utils::placeholder> &&values); executable_query values(std::vector<utils::placeholder> &&values);
query_values_intermediate values(std::vector<utils::database_type> &&values); executable_query values(std::vector<utils::database_type> &&values);
template<class Type> template<class Type>
query_values_intermediate values(const Type &obj) { executable_query values(const Type &obj) {
return values(value_extractor::extract(obj)); return values(value_extractor::extract(obj));
} }
}; };

View File

@ -317,7 +317,8 @@ private:
/** /**
* Represents the SQL VALUES part * Represents the SQL VALUES part
*/ */
class query_values_part final : public query_part { class query_values_part final : public query_part
{
public: public:
explicit query_values_part(std::vector<std::variant<utils::placeholder, utils::database_type>> &&values); explicit query_values_part(std::vector<std::variant<utils::placeholder, utils::database_type>> &&values);
@ -330,19 +331,6 @@ private:
std::vector<std::variant<utils::placeholder, utils::database_type>> values_; std::vector<std::variant<utils::placeholder, utils::database_type>> values_;
}; };
class query_returning_part final : public query_part {
public:
explicit query_returning_part(std::vector<table_column> columns);
[[nodiscard]] const std::vector<table_column>& columns() const;
private:
void accept(query_part_visitor &visitor) override;
private:
std::vector<table_column> columns_;
};
class query_update_part final : public query_part class query_update_part final : public query_part
{ {
public: public:

View File

@ -44,6 +44,7 @@ protected:
void visit(internal::query_drop_key_constraint_part_by_name &part) override; void visit(internal::query_drop_key_constraint_part_by_name &part) override;
void visit(internal::query_drop_key_constraint_part_by_constraint &part) override; void visit(internal::query_drop_key_constraint_part_by_constraint &part) override;
protected:
void visit(internal::query_select_part &part) override; void visit(internal::query_select_part &part) override;
void visit(internal::query_from_part &part) override; void visit(internal::query_from_part &part) override;
void visit(internal::query_join_table_part &part) override; void visit(internal::query_join_table_part &part) override;
@ -56,11 +57,9 @@ protected:
void visit(internal::query_order_by_desc_part &part) override; void visit(internal::query_order_by_desc_part &part) override;
void visit(internal::query_offset_part &part) override; void visit(internal::query_offset_part &part) override;
void visit(internal::query_limit_part &part) override; void visit(internal::query_limit_part &part) override;
void visit(internal::query_insert_part &part) override; void visit(internal::query_insert_part &part) override;
void visit(internal::query_into_part &part) override; void visit(internal::query_into_part &part) override;
void visit(internal::query_values_part &part) override; void visit(internal::query_values_part &part) override;
void visit(internal::query_returning_part &part) override;
void visit(internal::query_update_part &part) override; void visit(internal::query_update_part &part) override;
void visit(internal::query_set_part &part) override; void visit(internal::query_set_part &part) override;

View File

@ -4,9 +4,7 @@
namespace matador::query { namespace matador::query {
namespace internal { namespace internal {
// Alter common
class query_alter_part; class query_alter_part;
// Alter table
class query_alter_table_part; class query_alter_table_part;
class query_add_key_constraint_part; class query_add_key_constraint_part;
class query_drop_key_constraint_part_by_name; class query_drop_key_constraint_part_by_name;
@ -15,7 +13,6 @@ class query_add_foreign_key_constraint_part;
class query_add_constraint_part_by_constraint; class query_add_constraint_part_by_constraint;
class query_add_foreign_key_reference_part; class query_add_foreign_key_reference_part;
class query_add_primary_key_constraint_part; class query_add_primary_key_constraint_part;
// Select
class query_select_part; class query_select_part;
class query_from_part; class query_from_part;
class query_join_table_part; class query_join_table_part;
@ -28,30 +25,20 @@ class query_order_by_asc_part;
class query_order_by_desc_part; class query_order_by_desc_part;
class query_offset_part; class query_offset_part;
class query_limit_part; class query_limit_part;
// Insert
class query_insert_part; class query_insert_part;
class query_into_part; class query_into_part;
class query_values_part; class query_values_part;
class query_returning_part;
// Update
class query_update_part; class query_update_part;
class query_set_part; class query_set_part;
// Delete
class query_delete_part; class query_delete_part;
class query_delete_from_part; class query_delete_from_part;
// Create common
class query_create_part; class query_create_part;
// Create table
class query_create_table_part; class query_create_table_part;
class query_create_table_columns_part; class query_create_table_columns_part;
class query_create_table_constraints_part; class query_create_table_constraints_part;
// Create schema
class query_create_schema_part; class query_create_schema_part;
// Drop common
class query_drop_part; class query_drop_part;
// Drop table
class query_drop_table_part; class query_drop_table_part;
// Drop schema
class query_drop_schema_part; class query_drop_schema_part;
} }
@ -85,7 +72,6 @@ public:
virtual void visit(internal::query_insert_part &part) = 0; virtual void visit(internal::query_insert_part &part) = 0;
virtual void visit(internal::query_into_part &part) = 0; virtual void visit(internal::query_into_part &part) = 0;
virtual void visit(internal::query_values_part &part) = 0; virtual void visit(internal::query_values_part &part) = 0;
virtual void visit(internal::query_returning_part &part) = 0;
virtual void visit(internal::query_update_part &part) = 0; virtual void visit(internal::query_update_part &part) = 0;
virtual void visit(internal::query_set_part &part) = 0; virtual void visit(internal::query_set_part &part) = 0;

View File

@ -12,7 +12,6 @@ class dialect;
namespace matador::query { namespace matador::query {
class table_column; class table_column;
void prepare_column(std::string &out, const sql::dialect& d, const table_column &col);
[[nodiscard]] std::string prepare_identifier(const sql::dialect& d, const table_column &col); [[nodiscard]] std::string prepare_identifier(const sql::dialect& d, const table_column &col);
[[nodiscard]] std::string prepare_criteria(const sql::dialect& d, const table_column &col); [[nodiscard]] std::string prepare_criteria(const sql::dialect& d, const table_column &col);
} }

View File

@ -166,7 +166,6 @@ public:
[[nodiscard]] const std::string& primary_key() const; [[nodiscard]] const std::string& primary_key() const;
[[nodiscard]] const std::string& references() const; [[nodiscard]] const std::string& references() const;
[[nodiscard]] const std::string& remove() const; [[nodiscard]] const std::string& remove() const;
[[nodiscard]] const std::string& returning() const;
[[nodiscard]] const std::string& rollback() const; [[nodiscard]] const std::string& rollback() const;
[[nodiscard]] const std::string& schema() const; [[nodiscard]] const std::string& schema() const;
[[nodiscard]] const std::string& select() const; [[nodiscard]] const std::string& select() const;
@ -237,7 +236,6 @@ private:
{dialect_token::PrimaryKey, "PRIMARY KEY"}, {dialect_token::PrimaryKey, "PRIMARY KEY"},
{dialect_token::References, "REFERENCES"}, {dialect_token::References, "REFERENCES"},
{dialect_token::Remove, "DELETE"}, {dialect_token::Remove, "DELETE"},
{dialect_token::Returning, "RETURNING"},
{dialect_token::Rollback, "ROLLBACK TRANSACTION"}, {dialect_token::Rollback, "ROLLBACK TRANSACTION"},
{dialect_token::Schema, "SCHEMA"}, {dialect_token::Schema, "SCHEMA"},
{dialect_token::Select, "SELECT"}, {dialect_token::Select, "SELECT"},

View File

@ -51,7 +51,6 @@ enum class dialect_token : uint8_t {
PrimaryKey, PrimaryKey,
References, References,
Remove, Remove,
Returning,
Rollback, Rollback,
Schema, Schema,
Select, Select,

View File

@ -1,14 +1,11 @@
#ifndef MATADOR_EXECUTE_RESULT_HPP #ifndef MATADOR_EXECUTE_RESULT_HPP
#define MATADOR_EXECUTE_RESULT_HPP #define MATADOR_EXECUTE_RESULT_HPP
#include "matador/utils/identifier.hpp"
#include <vector> #include <vector>
namespace matador::sql { namespace matador::sql {
struct execute_result { struct execute_result {
size_t affected_rows{}; size_t affected_rows{};
std::vector<utils::identifier> generated_ids{}; std::vector<long long> insert_ids{};
}; };
} }
#endif // MATADOR_EXECUTE_RESULT_HPP #endif // MATADOR_EXECUTE_RESULT_HPP

View File

@ -27,10 +27,9 @@ enum class sql_command {
AlterSchema AlterSchema
}; };
enum class return_mode { struct sql_command_info {
None, std::string sql;
GeneratedKeys, sql_command command{};
Rows
}; };
struct query_context { struct query_context {
@ -45,14 +44,6 @@ struct query_context {
// Data for resolving query result // Data for resolving query result
std::shared_ptr<resolver_service> resolver{}; std::shared_ptr<resolver_service> resolver{};
std::type_index result_type = typeid(void); std::type_index result_type = typeid(void);
return_mode mode = return_mode::None;
[[nodiscard]] bool is_ddl() const { return command == sql_command::Create || command == sql_command::Alter; }
[[nodiscard]] bool is_dml() const { return command == sql_command::Insert || command == sql_command::Update || command == sql_command::Delete; }
[[nodiscard]] bool is_query() const { return command == sql_command::Select; }
[[nodiscard]] bool expects_rows() const { return mode == return_mode::Rows; }
[[nodiscard]] bool expects_generated_keys() const { return mode == return_mode::GeneratedKeys; }
}; };
} }

View File

@ -9,14 +9,20 @@
namespace matador::sql { namespace matador::sql {
class record final { class record final {
private:
using field_ref = std::reference_wrapper<field>;
using field_by_index = std::vector<field_ref>;
using field_index_pair = std::pair<field, field_by_index::difference_type>;
using field_by_name_map = std::unordered_map<std::string, field_index_pair>;
public: public:
using iterator = std::vector<field>::iterator; using iterator = field_by_index::iterator;
using const_iterator = std::vector<field>::const_iterator; using const_iterator = field_by_index::const_iterator;
record() = default; record() = default;
record(std::initializer_list<field> columns); record(std::initializer_list<field> columns);
explicit record(const std::vector<field> &columns); explicit record(const std::vector<field> &columns);
record(const record &x) = default; record(const record &x);
record& operator=(const record &x); record& operator=(const record &x);
record(record&&) noexcept = default; record(record&&) noexcept = default;
record& operator=(record&&) noexcept = default; record& operator=(record&&) noexcept = default;
@ -28,13 +34,13 @@ public:
template<class Operator> template<class Operator>
void process(Operator &op) { void process(Operator &op) {
for(auto &f : fields_) { for(auto &f : fields_) {
f.process(op); f.get().process(op);
} }
} }
void append(field col); void append(const field &col);
[[nodiscard]] const std::vector<field>& columns() const; [[nodiscard]] const std::vector<field_ref>& columns() const;
[[nodiscard]] const field& at(const std::string &name) const; [[nodiscard]] const field& at(const std::string &name) const;
[[nodiscard]] const field& at(size_t index) const; [[nodiscard]] const field& at(size_t index) const;
@ -65,8 +71,12 @@ public:
void clear(); void clear();
private: private:
std::vector<field> fields_; void init();
std::unordered_map<std::string, std::size_t> index_by_name_; void add_to_map(field &col, size_t index);
private:
field_by_index fields_;
field_by_name_map fields_by_name_;
}; };
} }

View File

@ -4,21 +4,18 @@
#include "matador/query/query_data.hpp" #include "matador/query/query_data.hpp"
namespace matador::query { namespace matador::query {
fetchable_query query_values_intermediate::returning(const table_column &col) {
context_->parts.push_back(std::make_unique<internal::query_returning_part>(std::vector{col}));
return {context_};
}
query_values_intermediate query_into_intermediate::values(const std::initializer_list<std::variant<utils::placeholder, utils::database_type>> values) { executable_query query_into_intermediate::values(const std::initializer_list<std::variant<utils::placeholder, utils::database_type>> values)
{
return this->values(std::vector(values)); return this->values(std::vector(values));
} }
query_values_intermediate query_into_intermediate::values(std::vector<std::variant<utils::placeholder, utils::database_type>> &&values) { executable_query query_into_intermediate::values(std::vector<std::variant<utils::placeholder, utils::database_type>> &&values) {
context_->parts.push_back(std::make_unique<internal::query_values_part>(std::move(values))); context_->parts.push_back(std::make_unique<internal::query_values_part>(std::move(values)));
return {context_}; return {context_};
} }
query_values_intermediate query_into_intermediate::values(std::vector<utils::placeholder>&& values) { executable_query query_into_intermediate::values(std::vector<utils::placeholder>&& values) {
std::vector<std::variant<utils::placeholder, utils::database_type>> transformed_values; std::vector<std::variant<utils::placeholder, utils::database_type>> transformed_values;
transformed_values.reserve(values.size()); transformed_values.reserve(values.size());
for (auto&& val : values) { for (auto&& val : values) {
@ -27,7 +24,7 @@ query_values_intermediate query_into_intermediate::values(std::vector<utils::pla
return this->values(std::move(transformed_values)); return this->values(std::move(transformed_values));
} }
query_values_intermediate query_into_intermediate::values(std::vector<utils::database_type>&& values) { executable_query query_into_intermediate::values(std::vector<utils::database_type>&& values) {
std::vector<std::variant<utils::placeholder, utils::database_type>> transformed_values; std::vector<std::variant<utils::placeholder, utils::database_type>> transformed_values;
transformed_values.reserve(values.size()); transformed_values.reserve(values.size());
for (auto&& val : values) { for (auto&& val : values) {

View File

@ -311,19 +311,6 @@ void query_values_part::accept(query_part_visitor &visitor) {
visitor.visit(*this); visitor.visit(*this);
} }
query_returning_part::query_returning_part(std::vector<table_column> columns)
: query_part(sql::dialect_token::Returning)
, columns_(std::move(columns)) {
}
const std::vector<table_column> & query_returning_part::columns() const {
return columns_;
}
void query_returning_part::accept(query_part_visitor &visitor) {
visitor.visit(*this);
}
query_update_part::query_update_part(class table tab) query_update_part::query_update_part(class table tab)
: query_part(sql::dialect_token::Update) : query_part(sql::dialect_token::Update)
, table_(std::move(tab)) { , table_(std::move(tab)) {

View File

@ -36,10 +36,16 @@ sql::query_context query_builder::compile(const query_data &data,
return {query_}; return {query_};
} }
void build_columns_with_name_only(std::string &out, const std::vector<table_column> &cols, const sql::dialect &d); std::string handle_column(sql::query_context &ctx, const sql::dialect *d, const table_column &col) {
void build_columns(std::string &out, const std::vector<table_column> &cols, const sql::dialect &d); if (col.is_function()) {
void build_fetchable_columns(sql::query_context &ctx, const std::vector<table_column> &cols, const sql::dialect &d); ctx.prototype.emplace_back(col.has_alias() ? col.alias() : col.canonical_name());
void prepare_prototype(std::vector<object::attribute> &prototype, const table_column &col); ctx.prototype.back().change_type(utils::basic_type::Int32);
} else {
ctx.prototype.emplace_back(col.has_alias() ? col.alias() : col.canonical_name());
}
return prepare_identifier(*d, col);
}
void query_builder::visit(internal::query_alter_part& part) { void query_builder::visit(internal::query_alter_part& part) {
query_.sql = dialect_->token_at(part.token()); query_.sql = dialect_->token_at(part.token());
@ -55,6 +61,9 @@ void query_builder::visit(internal::query_add_key_constraint_part& part) {
query_.sql += " " + dialect_->add_constraint() + " " + part.name(); query_.sql += " " + dialect_->add_constraint() + " " + part.name();
} }
void build_columns_with_name_only(std::string &out, const std::vector<table_column> &cols, const sql::dialect &d);
void build_columns(std::string &out, const std::vector<table_column> &cols, const sql::dialect &d);
void query_builder::visit(internal::query_add_foreign_key_constraint_part& part) { void query_builder::visit(internal::query_add_foreign_key_constraint_part& part) {
query_.sql += " " + dialect_->token_at(part.token()) + " ("; query_.sql += " " + dialect_->token_at(part.token()) + " (";
build_columns(query_.sql, part.columns(), *dialect_); build_columns(query_.sql, part.columns(), *dialect_);
@ -91,7 +100,23 @@ void query_builder::visit(internal::query_select_part &part) {
query_.prototype.clear(); query_.prototype.clear();
build_fetchable_columns(query_, part.columns(), *dialect_); std::string result;
if (part.columns().empty()) {
result = dialect_->asterisk();
} else if (const auto &columns = part.columns(); columns.size() < 2) {
for (const auto &col: columns) {
result.append(handle_column(query_, dialect_, col ));
}
} else {
auto it = columns.begin();
result.append(handle_column(query_, dialect_, *it++));
for (; it != columns.end(); ++it) {
result.append(", ");
result.append(handle_column(query_, dialect_, *it));
}
}
query_.sql += result;
} }
void query_builder::visit(internal::query_from_part &part) { void query_builder::visit(internal::query_from_part &part) {
@ -240,20 +265,15 @@ void query_builder::visit(internal::query_values_part &part) {
query_.sql += " " + result; query_.sql += " " + result;
} }
void query_builder::visit(internal::query_returning_part &part) { void query_builder::visit(internal::query_update_part &part)
query_.mode = sql::return_mode::Rows; {
query_.sql += " " + dialect_->returning() + " ";
build_fetchable_columns(query_, part.columns(), *dialect_);
}
void query_builder::visit(internal::query_update_part &part) {
query_.command = sql::sql_command::Update; query_.command = sql::sql_command::Update;
query_.table_name = part.table().name(); query_.table_name = part.table().name();
query_.sql += build_table_name(part.token(), *dialect_, query_.table_name); query_.sql += query_builder::build_table_name(part.token(), *dialect_, query_.table_name);
} }
void query_builder::visit(internal::query_delete_part &/*delete_part*/) { void query_builder::visit(internal::query_delete_part &/*delete_part*/)
{
query_.command = sql::sql_command::Delete; query_.command = sql::sql_command::Delete;
query_.sql = dialect_->remove(); query_.sql = dialect_->remove();
} }
@ -388,27 +408,6 @@ void build_columns(std::string &out, const std::vector<table_column> &cols, con
} }
} }
void build_fetchable_columns(sql::query_context &ctx, const std::vector<table_column> &cols, const sql::dialect &d) {
bool first = true;
for (const auto& col : cols) {
if (!first) {
ctx.sql.append(", ");
}
prepare_prototype(ctx.prototype, col);
prepare_column(ctx.sql, d, col);
first = false;
}
}
void prepare_prototype(std::vector<object::attribute> &prototype, const table_column &col) {
if (col.is_function()) {
prototype.emplace_back(col.has_alias() ? col.alias() : col.canonical_name());
prototype.back().change_type(utils::basic_type::Int32);
} else {
prototype.emplace_back(col.has_alias() ? col.alias() : col.canonical_name());
}
}
std::string build_constraint(const table_constraint& cons, const sql::dialect& d) { std::string build_constraint(const table_constraint& cons, const sql::dialect& d) {
std::string result; std::string result;
if (!cons.name().empty()) { if (!cons.name().empty()) {

View File

@ -4,18 +4,6 @@
#include "matador/query/internal/string_builder_utils.hpp" #include "matador/query/internal/string_builder_utils.hpp"
namespace matador::query { namespace matador::query {
void prepare_column(std::string &out, const sql::dialect &d, const table_column &col) {
if (!col.is_function()) {
prepare_identifier_string_append(out, col.name(), d);
} else {
if (col.column_name() == d.asterisk()) {
out += d.sql_function_at(col.function()) + "(" + col.column_name() + ")";
} else {
out += d.sql_function_at(col.function()) + "(" + col.column_name() + ") " + d.as() + " " + col.alias();
}
}
}
std::string prepare_identifier(const sql::dialect& d, const table_column& col) { std::string prepare_identifier(const sql::dialect& d, const table_column& col) {
std::string result; std::string result;
if (!col.is_function()) { if (!col.is_function()) {

View File

@ -271,10 +271,6 @@ const std::string &dialect::remove() const {
return token_at(dialect_token::Remove); return token_at(dialect_token::Remove);
} }
const std::string & dialect::returning() const {
return token_at(dialect_token::Returning);
}
const std::string &dialect::rollback() const { const std::string &dialect::rollback() const {
return token_at(dialect_token::Rollback); return token_at(dialect_token::Rollback);
} }

View File

@ -7,66 +7,76 @@ namespace matador::sql {
record::record(const std::initializer_list<field> columns) { record::record(const std::initializer_list<field> columns) {
for (auto &&col :columns) { for (auto &&col :columns) {
index_by_name_.emplace(col.name(), fields_.size()); const auto it = fields_by_name_.emplace(col.name(), field_index_pair {col, fields_.size()});
fields_.push_back(col); fields_.push_back(std::ref(it.first->second.first));
} }
} }
record::record(const std::vector<field> &columns) record::record(const std::vector<field> &columns) {
: fields_(columns) { for (auto &&col :columns) {
for (auto i = 0u; i < columns.size(); ++i) { const auto it = fields_by_name_.emplace(col.name(), field_index_pair {col, fields_.size()});
index_by_name_.emplace(columns[i].name(), i); fields_.push_back(std::ref(it.first->second.first));
} }
} }
record &record::operator=(const record &x) { record::record(const record &x)
: fields_by_name_(x.fields_by_name_)
{
for (auto& col : x.fields_) {
auto &it = fields_by_name_.at(col.get().name());
fields_.push_back(std::ref(it.first));
}
}
record &record::operator=(const record &x)
{
if (&x == this) { if (&x == this) {
return *this; return *this;
} }
fields_ = x.fields_; fields_by_name_ = x.fields_by_name_;
index_by_name_ = x.index_by_name_; fields_.clear();
// pk_index_ = x.pk_index_;
for (auto& col : x.fields_) {
auto &it = fields_by_name_.at(col.get().name());
fields_.push_back(std::ref(it.first));
}
return *this; return *this;
} }
const std::vector<field> &record::columns() const { const std::vector<record::field_ref> &record::columns() const {
return fields_; return fields_;
} }
const field &record::at(const std::string &name) const { const field &record::at(const std::string &name) const {
const auto it = index_by_name_.find(name); const auto &res = fields_by_name_.at(name);
if (it == index_by_name_.end()) { const auto &f = res.first;
throw std::out_of_range("Column not found"); return f;
} }
return fields_[it->second]; const field &record::at(const size_t index) const
} {
const field &record::at(const size_t index) const {
return fields_.at(index); return fields_.at(index);
} }
field &record::at(const std::string &name) { field &record::at(const std::string &name) {
const auto it = index_by_name_.find(name); auto &[fst, snd] = fields_by_name_.at(name);
if (it == index_by_name_.end()) { return fst;
throw std::out_of_range("Column not found");
}
return fields_[it->second];
} }
field &record::at(const size_t index) { field &record::at(const size_t index) {
return fields_.at(index); return fields_.at(index);
} }
record::iterator record::find(const std::string &column_name) { record::iterator record::find(const std::string &column_name)
const auto it = index_by_name_.find(column_name); {
return it != index_by_name_.end() ? fields_.begin() + static_cast<long>(it->second) : fields_.end(); auto it = fields_by_name_.find(column_name);
return it != fields_by_name_.end() ? fields_.begin() + it->second.second : fields_.end();
} }
record::const_iterator record::find(const std::string &column_name) const { record::const_iterator record::find(const std::string &column_name) const {
const auto it = index_by_name_.find(column_name); auto it = fields_by_name_.find(column_name);
return it != index_by_name_.end() ? fields_.begin() + static_cast<long>(it->second) : fields_.end(); return it != fields_by_name_.end() ? fields_.begin() + it->second.second : fields_.end();
} }
bool record::operator==(const record &rhs) const { bool record::operator==(const record &rhs) const {
@ -85,45 +95,68 @@ bool record::operator!=(const record &rhs) const {
return !operator==(rhs); return !operator==(rhs);
} }
void record::append(field col) { void record::append(const field &col) {
index_by_name_.emplace(col.name(), fields_.size()); const auto [fst, snd] = fields_by_name_.emplace(col.name(), field_index_pair {col, fields_.size()});
fields_.push_back(std::move(col)); fields_.push_back(std::ref(fst->second.first));
} }
record::iterator record::begin() { record::iterator record::begin()
{
return fields_.begin(); return fields_.begin();
} }
record::const_iterator record::begin() const { record::const_iterator record::begin() const
{
return fields_.begin(); return fields_.begin();
} }
record::const_iterator record::cbegin() const { record::const_iterator record::cbegin() const
{
return fields_.cbegin(); return fields_.cbegin();
} }
record::iterator record::end() { record::iterator record::end()
{
return fields_.end(); return fields_.end();
} }
record::const_iterator record::end() const { record::const_iterator record::end() const
{
return fields_.end(); return fields_.end();
} }
record::const_iterator record::cend() const { record::const_iterator record::cend() const
{
return fields_.cend(); return fields_.cend();
} }
size_t record::size() const { size_t record::size() const
{
return fields_.size(); return fields_.size();
} }
bool record::empty() const { bool record::empty() const
{
return fields_.empty(); return fields_.empty();
} }
void record::clear() { void record::clear()
{
fields_.clear(); fields_.clear();
index_by_name_.clear(); fields_by_name_.clear();
}
void record::init()
{
size_t index{0};
for(auto &col : fields_) {
add_to_map(col, index++);
} }
} }
void record::add_to_map(field &col, size_t index)
{
fields_by_name_.emplace(col.name(), field_index_pair {std::ref(col), index});
}
}

View File

@ -87,30 +87,6 @@ TEST_CASE_METHOD(QueryFixture, "Execute select statement with where clause", "[q
} }
} }
TEST_CASE_METHOD(QueryFixture, "Execute insert with returning", "[query][insert][returning]") {
REQUIRE(repo.attach<person>("persons"));
auto result = repo.create(db);
REQUIRE(result.is_ok());
check_table_exists(PERSON.table_name());
person george{7, "george", 45};
george.image.emplace_back(37);
auto res = query::insert()
.into(PERSON, {PERSON.id, PERSON.name, PERSON.age, PERSON.image})
.values(george)
.returning(PERSON.id)
.fetch_one(db);
REQUIRE(res.is_ok());
auto rec = res.release();
REQUIRE(rec->size() == 1);
REQUIRE(rec->at(0).name() == "persons.id");
REQUIRE(rec->at(0).is_integer());
REQUIRE(rec->at(0).as<uint32_t>() == 7);
}
TEST_CASE_METHOD(QueryFixture, "Execute insert statement", "[query][insert]") { TEST_CASE_METHOD(QueryFixture, "Execute insert statement", "[query][insert]") {
auto res = query::create() auto res = query::create()
.table("person") .table("person")

View File

@ -33,19 +33,22 @@ record_printer::record_printer(std::ostream &os)
} }
void record_printer::print_header(const sql::record &rec) const { void record_printer::print_header(const sql::record &rec) const {
for (const auto &f: rec.columns()) { for (const auto &f_ref: rec.columns()) {
const auto &f = f_ref.get();
os_ << std::left << std::setw(width(f)) << f.name() << " "; os_ << std::left << std::setw(width(f)) << f.name() << " ";
} }
os_ << "\n"; os_ << "\n";
for (const auto &f: rec.columns()) { for (const auto &f_ref: rec.columns()) {
const auto &f = f_ref.get();
os_ << std::string(width(f), '-') << " "; os_ << std::string(width(f), '-') << " ";
} }
os_ << "\n"; os_ << "\n";
} }
void record_printer::print(const sql::record &rec) const { void record_printer::print(const sql::record &rec) const {
for (const auto &f: rec.columns()) { for (const auto &f_ref: rec.columns()) {
const auto &f = f_ref.get();
os_ << std::left << std::setw(width(f)) << f.str() << " "; os_ << std::left << std::setw(width(f)) << f.str() << " ";
} }
os_ << "\n"; os_ << "\n";

16
todo.md
View File

@ -1,25 +1,13 @@
# Todo # Todo
- move `prepare_*` methods from `dialect` to `query_compiler` - move `prepare_*` methods from `dialect` to `query_compiler`
- add `insert_query_builder` and `update_update_builder` (returning multiple statements) - add `session_insert_builder` and `session_update_builder` (returning multiple statements)
- finish fetch eager many-to-many relations - finish fetch eager many-to-many relations
- implement lazy loading - implement lazy loading
- implement polymorphic class hierarchies - implement polymorphic class hierarchies
- finish `database` (schema_repository) class (move add/drop from `session` to `schema`) - finish `schema_repository` classes (move add/drop from `session` to `schema`)
- implement a flag class for enumerations - implement a flag class for enumerations
- PK generator
1. Introduce execute_context
2. Introduce execute_result
3. Add `abstract_pk_generator` class
4. Add `identity_pk_generator` class
5. Add `sequence_pk_generator` class
6. Add `table_pk_generator` class
7. Add `manual_pk_generator` class
8. Extend `session::insert` logic to use pk generator
9. Extend `postgres_connection::execute` to handle `returning` clause
10. Add generator to `schema_node` or `table` class when attaching type
11. Extend `query_builder` and `intermediates` with `returning` intermediate
__Proposal for polymorphic classes:__ __Proposal for polymorphic classes:__