progress on query compiler

This commit is contained in:
Sascha Kühl 2026-01-22 16:14:42 +01:00
parent b331ef6923
commit 686b1ddb7a
19 changed files with 241 additions and 175 deletions

View File

@ -219,3 +219,51 @@ int main() {
return 0; return 0;
} }
/*
SELECT
"tasks"."payload", "payloads"."id"
FROM
"public"."tasks", "public"."payloads"
WHERE
"payloads"."id" = "tasks"."payload"
SELECT
"iPT"."payload_id" FROM "public"."id_payloads" "iPT"
LEFT JOIN
"public"."payloads" "pT"
ON
"iPT"."id" = "pT"."id"
WHERE ("pT"."id" IN (
SELECT
"jobs"."payload"
FROM
"public"."jobs"
WHERE
"jobs"."state" = $1
) AND "iPT"."payload_id" IN (
SELECT
"ID"
FROM "public"."TempTable"
)
)
SELECT
"login_histories"."client"
FROM
"public"."login_histories"
LEFT JOIN (
SELECT
"login_histories"."client", MAX(login_time) AS lastSuccessfulLogin
FROM
"public"."login_histories"
WHERE
"login_histories"."fail_reason" = $1
GROUP BY
"login_histories"."client"
)
ON
"login_histories"."client" = 'll.client'
WHERE
("lastSuccessfulLogin" IS NULL AND "login_histories"."login_time" < 'll.lastSuccessfulLogin')
*/

View File

@ -0,0 +1,14 @@
#ifndef MATADOR_STRING_BUILDER_UTILS_HPP
#define MATADOR_STRING_BUILDER_UTILS_HPP
#include <string>
namespace matador::sql {
class dialect;
}
namespace matador::query {
void prepare_identifier_string_append(std::string& out, std::string_view col, const sql::dialect &d);
}
#endif // MATADOR_STRING_BUILDER_UTILS_HPP

View File

@ -14,8 +14,8 @@ table_column count(const std::string &column);
table_column count_all(); table_column count_all();
table_column sum(const std::string &column); table_column sum(const std::string &column);
table_column avg(const std::string &column); table_column avg(const std::string &column);
table_column max(const std::string &column); table_column maximum(const std::string &column);
table_column min(const std::string &column); table_column minimum(const std::string &column);
class query class query
{ {

View File

@ -16,13 +16,19 @@ class table;
class table_column { class table_column {
public: public:
table_column(const char *name); // NOLINT(*-explicit-constructor) table_column(const char *name); // NOLINT(*-explicit-constructor)
table_column(std::string name); // NOLINT(*-explicit-constructor) table_column(const std::string& name); // NOLINT(*-explicit-constructor)
table_column(std::string name, std::string alias); table_column(const std::string& name, const std::string& alias);
table_column(sql::sql_function_t func, std::string name); table_column(sql::sql_function_t func, const std::string& name);
table_column(const class table* tab, std::string name); table_column(const class table* tab, const std::string& name);
table_column(const class table* tab, std::string name, std::string alias); table_column(const class table* tab, const std::string& name,
table_column(const class table* tab, std::string name, utils::basic_type type, const utils::field_attributes& attributes); const std::string& alias);
table_column(const class table*, std::string name, std::string alias, utils::basic_type type, const utils::field_attributes& attributes, sql::sql_function_t func = sql::sql_function_t::None); table_column(const class table* tab, const std::string& name, utils::basic_type type, const utils::field_attributes& attributes);
table_column(const class table*,
const std::string& name,
const std::string& alias,
utils::basic_type type,
const utils::field_attributes& attributes,
sql::sql_function_t func = sql::sql_function_t::None);
table_column& operator=(const table_column& other); table_column& operator=(const table_column& other);
table_column(const table_column& other) = default; table_column(const table_column& other) = default;
table_column(table_column&& other) noexcept = default; table_column(table_column&& other) noexcept = default;
@ -30,10 +36,11 @@ public:
[[nodiscard]] bool equals(const table_column &x) const; [[nodiscard]] bool equals(const table_column &x) const;
table_column as(const std::string& alias) const; [[nodiscard]] table_column as(const std::string& alias) const;
[[nodiscard]] const std::string& name() const; [[nodiscard]] const std::string& name() const;
[[nodiscard]] std::string canonical_name() const; [[nodiscard]] const std::string& column_name() const;
[[nodiscard]] const std::string& canonical_name() const;
[[nodiscard]] const std::string& alias() const; [[nodiscard]] const std::string& alias() const;
[[nodiscard]] utils::basic_type type() const; [[nodiscard]] utils::basic_type type() const;
[[nodiscard]] utils::field_attributes attributes() const; [[nodiscard]] utils::field_attributes attributes() const;
@ -49,11 +56,15 @@ public:
// ReSharper disable once CppNonExplicitConversionOperator // ReSharper disable once CppNonExplicitConversionOperator
operator const std::string&() const; // NOLINT(*-explicit-constructor) operator const std::string&() const; // NOLINT(*-explicit-constructor)
private:
static std::string build_column_name(const class table *tab, const std::string& name);
private: private:
friend class table; friend class table;
const class table* table_{nullptr}; const class table* table_{nullptr};
std::string name_; std::string name_;
std::string column_name_;
std::string alias_; std::string alias_;
utils::basic_type type_{utils::basic_type::Unknown}; utils::basic_type type_{utils::basic_type::Unknown};
utils::field_attributes attributes_{}; utils::field_attributes attributes_{};

View File

@ -53,7 +53,6 @@ public:
* @return The prepared string * @return The prepared string
*/ */
[[nodiscard]] std::string prepare_identifier_string(const std::string &col) const; [[nodiscard]] std::string prepare_identifier_string(const std::string &col) const;
[[nodiscard]] std::string table_name(const std::string &table, const std::string &schema_name) const;
[[nodiscard]] const std::string& to_string(bool val) const; [[nodiscard]] const std::string& to_string(bool val) const;

View File

@ -48,6 +48,7 @@ add_library(matador-orm STATIC
../../include/matador/query/internal/basic_type_to_string_visitor.hpp ../../include/matador/query/internal/basic_type_to_string_visitor.hpp
../../include/matador/query/internal/column_value_pair.hpp ../../include/matador/query/internal/column_value_pair.hpp
../../include/matador/query/internal/query_parts.hpp ../../include/matador/query/internal/query_parts.hpp
../../include/matador/query/internal/string_builder_utils.hpp
../../include/matador/query/join_data.hpp ../../include/matador/query/join_data.hpp
../../include/matador/query/key_value_generator.hpp ../../include/matador/query/key_value_generator.hpp
../../include/matador/query/meta_table_macro.hpp ../../include/matador/query/meta_table_macro.hpp
@ -142,6 +143,7 @@ add_library(matador-orm STATIC
query/internal/column_value_pair.cpp query/internal/column_value_pair.cpp
query/internal/query_parts.cpp query/internal/query_parts.cpp
query/internal/query_result_impl.cpp query/internal/query_result_impl.cpp
query/internal/string_builder_utils.cpp
query/key_value_generator.cpp query/key_value_generator.cpp
query/query.cpp query/query.cpp
query/query_builder.cpp query/query_builder.cpp

View File

@ -40,7 +40,7 @@ std::string criteria_evaluator::evaluate(const abstract_criteria &node) {
void criteria_evaluator::visit(const between_criteria &node) { void criteria_evaluator::visit(const between_criteria &node) {
query_.bind_vars.emplace_back(node.col().name()); query_.bind_vars.emplace_back(node.col().name());
query_.bind_vars.emplace_back(node.col().name()); query_.bind_vars.emplace_back(node.col().name());
clause_ += prepare_identifier(dialect_, node.col()) + " " + dialect_.token_at(sql::dialect_token::Between) + " "; clause_ += prepare_identifier(dialect_, node.col()) + " " + dialect_.between() + " ";
evaluate_value(node.minimum()); evaluate_value(node.minimum());
clause_ += " " + dialect_.token_at(sql::dialect_token::And) + " "; clause_ += " " + dialect_.token_at(sql::dialect_token::And) + " ";
evaluate_value(node.maximum()); evaluate_value(node.maximum());
@ -94,12 +94,12 @@ void criteria_evaluator::visit(const collection_criteria &node) {
void criteria_evaluator::visit(const collection_query_criteria &node) { void criteria_evaluator::visit(const collection_query_criteria &node) {
clause_ += prepare_identifier(dialect_, node.col()) + clause_ += prepare_identifier(dialect_, node.col()) +
(node.operand() == collection_operator::Out ? " " + dialect_.token_at(sql::dialect_token::Not) + " " : " ") + (node.operand() == collection_operator::Out ? " " + dialect_.not_() + " " : " ") +
dialect_.token_at(sql::dialect_token::In) + " (" + node.query().str( dialect_ ) + ")"; dialect_.in() + " (" + node.query().str( dialect_ ) + ")";
} }
void criteria_evaluator::visit(const like_criteria &node) { void criteria_evaluator::visit(const like_criteria &node) {
clause_ += prepare_criteria(dialect_, node.col()) + " " + dialect_.token_at(sql::dialect_token::Like) + clause_ += prepare_criteria(dialect_, node.col()) + " " + dialect_.like() +
" " + dialect_.token_at(sql::dialect_token::BeginStringData) + node.pattern() + dialect_.token_at( " " + dialect_.token_at(sql::dialect_token::BeginStringData) + node.pattern() + dialect_.token_at(
sql::dialect_token::EndStringData); sql::dialect_token::EndStringData);
} }

View File

@ -0,0 +1,40 @@
#include "matador/query/internal/string_builder_utils.hpp"
#include "matador/sql/dialect.hpp"
namespace matador::query {
void prepare_identifier_string_append(std::string& out, const std::string_view col, const sql::dialect &d) {
bool first_part = true;
const char sq = d.start_quote()[0];
const char eq = d.end_quote()[0];
std::size_t i = 0;
while (true) {
const std::size_t start = i;
// find end of part
while (i < col.size() && col[i] != '.') {
++i;
}
const std::size_t end = i; // [start, end) is the part
if (!first_part) {
out.push_back('.');
}
first_part = false;
// quote_identifier(part) + escape_quotes_in_identifier(part), but streaming:
out.push_back(sq);
for (std::size_t j = start; j < end; ++j) {
const char c = col[j];
if (c == eq) out.push_back(eq); // escape " as ""
out.push_back(c);
}
out.push_back(eq);
if (i >= col.size()) break; // done
++i; // skip '.'
}
}
}

View File

@ -15,10 +15,10 @@ table_column sum(const std::string& column) {
table_column avg(const std::string& column) { table_column avg(const std::string& column) {
return {sql::sql_function_t::Avg, column}; return {sql::sql_function_t::Avg, column};
} }
table_column max(const std::string& column) { table_column maximum(const std::string& column) {
return {sql::sql_function_t::Max, column}; return {sql::sql_function_t::Max, column};
} }
table_column min(const std::string& column) { table_column minimum(const std::string& column) {
return {sql::sql_function_t::Min, column}; return {sql::sql_function_t::Min, column};
} }

View File

@ -8,14 +8,13 @@
#include "matador/query/table_column.hpp" #include "matador/query/table_column.hpp"
#include "matador/query/internal/basic_type_to_string_visitor.hpp" #include "matador/query/internal/basic_type_to_string_visitor.hpp"
#include "matador/query/internal/string_builder_utils.hpp"
#include "matador/query/internal/query_parts.hpp" #include "matador/query/internal/query_parts.hpp"
#include "matador/sql/query_context.hpp" #include "matador/sql/query_context.hpp"
#include "matador/sql/connection.hpp" #include "matador/sql/connection.hpp"
#include "matador/sql/dialect.hpp" #include "matador/sql/dialect.hpp"
#include "matador/utils/string.hpp"
namespace matador::query { namespace matador::query {
sql::query_context query_compiler::compile(const query_data &data, sql::query_context query_compiler::compile(const query_data &data,
@ -39,10 +38,10 @@ sql::query_context query_compiler::compile(const query_data &data,
std::string handle_column(sql::query_context &ctx, const sql::dialect *d, const query_data &data, const table_column &col) { std::string handle_column(sql::query_context &ctx, const sql::dialect *d, const query_data &data, const table_column &col) {
if (col.is_function()) { if (col.is_function()) {
ctx.prototype.emplace_back(col.has_alias() ? col.alias() : col.canonical_name()); ctx.prototype.emplace_back(col.name());
ctx.prototype.back().change_type(utils::basic_type::Int32); ctx.prototype.back().change_type(utils::basic_type::Int32);
} else { } else {
ctx.prototype.emplace_back(col.canonical_name()); ctx.prototype.emplace_back(col.name());
} }
@ -69,54 +68,23 @@ void query_compiler::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(std::string &out, const std::vector<table_column> &cols, const sql::dialect &d);
void query_compiler::visit(internal::query_add_foreign_key_constraint_part& part) { void query_compiler::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_);
if (part.columns().size() < 2) {
for (const auto &col: part.columns()) {
query_.sql += dialect_->prepare_identifier_string(col.name());
}
} else {
auto it = part.columns().begin();
query_.sql += dialect_->prepare_identifier_string(it->name());
for (; it != part.columns().end(); ++it) {
query_.sql += ", " + dialect_->prepare_identifier_string(it->name());
}
}
query_.sql += ")"; query_.sql += ")";
} }
void query_compiler::visit(internal::query_add_primary_key_constraint_part& part) { void query_compiler::visit(internal::query_add_primary_key_constraint_part& part) {
query_.sql += " " + dialect_->primary_key() + " ("; query_.sql += " " + dialect_->primary_key() + " (";
build_columns(query_.sql, part.columns(), *dialect_);
if (part.columns().size() < 2) {
for (const auto &col: part.columns()) {
query_.sql += dialect_->prepare_identifier_string(col.name());
}
} else {
auto it = part.columns().begin();
query_.sql += dialect_->prepare_identifier_string(it->name());
for (; it != part.columns().end(); ++it) {
query_.sql += ", " + dialect_->prepare_identifier_string(it->name());
}
}
query_.sql += ")"; query_.sql += ")";
} }
void query_compiler::visit(internal::query_add_foreign_key_reference_part& part) { void query_compiler::visit(internal::query_add_foreign_key_reference_part& part) {
query_.sql += " " + dialect_->token_at(part.token()) + " " + part.table().name() + " ("; query_.sql += " " + dialect_->token_at(part.token()) + " " + part.table().name() + " (";
build_columns(query_.sql, part.columns(), *dialect_);
if (part.columns().size() < 2) {
for (const auto &col: part.columns()) {
query_.sql += dialect_->prepare_identifier_string(col.name());
}
} else {
auto it = part.columns().begin();
query_.sql += dialect_->prepare_identifier_string(it->name());
for (; it != part.columns().end(); ++it) {
query_.sql += ", " + dialect_->prepare_identifier_string(it->name());
}
}
query_.sql += ")"; query_.sql += ")";
} }
@ -198,7 +166,7 @@ void query_compiler::visit(internal::query_group_by_part &part) {
query_.sql += " " + dialect_->group_by() + " "; query_.sql += " " + dialect_->group_by() + " ";
if (part.columns().size() < 2) { if (part.columns().size() < 2) {
for (const auto &col: part.columns()) { for (const auto &col: part.columns()) {
query_.sql.append(dialect_->prepare_identifier_string(col.canonical_name())); query_.sql.append(dialect_->prepare_identifier_string(col.name()));
} }
} else { } else {
auto it = part.columns().begin(); auto it = part.columns().begin();
@ -250,23 +218,10 @@ void query_compiler::visit(internal::query_insert_part &/*insert_part*/) {
void query_compiler::visit(internal::query_into_part &part) { void query_compiler::visit(internal::query_into_part &part) {
query_.table_name = part.table().name(); query_.table_name = part.table().name();
query_.sql += " " + dialect_->into() + query_.sql += " " + dialect_->into() +
" " + dialect_->prepare_identifier_string(part.table().name()); " " + dialect_->prepare_identifier_string(part.table().name()) + " (";
std::string result{"("}; build_columns(query_.sql, part.columns(), *dialect_);
if (part.columns().size() < 2) { query_.sql += ")"/* + result*/;
for (const auto &col: part.columns()) {
result.append(dialect_->prepare_identifier_string(col.name()));
}
} else {
auto it = part.columns().begin();
result.append(dialect_->prepare_identifier_string((it++)->name()));
for (; it != part.columns().end(); ++it) {
result.append(", ");
result.append(dialect_->prepare_identifier_string(it->name()));
}
}
result += (")");
query_.sql += " " + result;
} }
struct value_visitor { struct value_visitor {
@ -341,7 +296,7 @@ void query_compiler::visit(internal::query_create_part &/*create_part*/)
query_.sql = dialect_->create(); query_.sql = dialect_->create();
} }
std::string build_create_column(const table_column &col, const sql::dialect &d); void build_create_column(std::string &out, const table_column &col, const sql::dialect &d);
std::string build_constraint(const table_constraint &cons, const sql::dialect &d); std::string build_constraint(const table_constraint &cons, const sql::dialect &d);
void query_compiler::visit(internal::query_create_table_part &part) void query_compiler::visit(internal::query_create_table_part &part)
@ -353,24 +308,16 @@ void query_compiler::visit(internal::query_create_table_part &part)
} }
void query_compiler::visit(internal::query_create_table_columns_part& part) { void query_compiler::visit(internal::query_create_table_columns_part& part) {
std::string result; bool first = true;
if (part.columns().size() < 2) {
for (const auto& col : part.columns()) { for (const auto& col : part.columns()) {
result.append(build_create_column(col, *dialect_)); if (!first) {
query_.sql.append(", ");
} }
} else { build_create_column(query_.sql, col, *dialect_);
auto it = part.columns().begin(); first = false;
result.append(build_create_column(*it++, *dialect_));
for (; it != part.columns().end(); ++it) {
result.append(", ");
result.append(build_create_column(*it, *dialect_));
} }
} }
query_.sql += result;
}
void query_compiler::visit(internal::query_create_table_constraints_part& part) { void query_compiler::visit(internal::query_create_table_constraints_part& part) {
std::string result; std::string result;
for (const auto& c : part.constraints()) { for (const auto& c : part.constraints()) {
@ -425,22 +372,31 @@ void query_compiler::visit(internal::query_drop_table_part &part) {
query_.sql += " " + build_table_name(part.token(), *dialect_, query_.table_name); query_.sql += " " + build_table_name(part.token(), *dialect_, query_.table_name);
} }
std::string build_create_column(const table_column &col, const sql::dialect &d) { void build_create_column(std::string &out, const table_column &col, const sql::dialect &d) {
std::string result = d.prepare_identifier_string(col.name()) + " " + d.data_type_at(col.type()); prepare_identifier_string_append(out, col.canonical_name(), d);
out += " " + d.data_type_at(col.type());
if (col.attributes().size() > 0) { if (col.attributes().size() > 0) {
result.append("(" + std::to_string(col.attributes().size()) + ")"); out.append("(" + std::to_string(col.attributes().size()) + ")");
} }
if (!col.is_nullable()) { if (!col.is_nullable()) {
result.append(" ").append(d.not_null()); out.append(" ").append(d.not_null());
} }
if (is_constraint_set(col.attributes().options(), utils::constraints::Unique)) { if (is_constraint_set(col.attributes().options(), utils::constraints::Unique)) {
result.append(" ").append(d.unique()); out.append(" ").append(d.unique());
} }
if (is_constraint_set(col.attributes().options(), utils::constraints::PrimaryKey)) { if (is_constraint_set(col.attributes().options(), utils::constraints::PrimaryKey)) {
result.append(" ").append(d.primary_key()); out.append(" ").append(d.primary_key());
}
}
void build_columns(std::string &out, const std::vector<table_column> &cols, const sql::dialect &d) {
bool first = true;
for (const auto& col : cols) {
if (!first) {
out.append(", ");
}
prepare_identifier_string_append(out, col.name(), d);
first = false;
} }
return result;
} }
std::string build_constraint(const table_constraint& cons, const sql::dialect& d) { std::string build_constraint(const table_constraint& cons, const sql::dialect& d) {

View File

@ -1,31 +1,23 @@
#include "matador/query/query_utils.hpp" #include "matador/query/query_utils.hpp"
#include "matador/query/table.hpp" #include "matador/query/table.hpp"
#include "matador/query/internal/string_builder_utils.hpp"
namespace matador::query { namespace matador::query {
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()) {
if (col.table()) { prepare_identifier_string_append(result, col.name(), d);
result = d.prepare_identifier_string(col.table()->name()) + ".";
}
result += d.prepare_identifier_string(col.name());
} else { } else {
result = d.sql_function_at(col.function()) + "(" + col.name() + ")"; result = d.sql_function_at(col.function()) + "(" + col.name() + ")";
} }
if (!col.alias().empty()) {
result += " AS " + col.alias();
}
return result; return result;
} }
std::string prepare_criteria(const sql::dialect& d, const table_column& col) { std::string prepare_criteria(const sql::dialect& d, const table_column& col) {
std::string result; std::string result;
if (!col.is_function()) { if (!col.is_function()) {
if (col.table()) { prepare_identifier_string_append(result, col.name(), d);
result = d.prepare_identifier_string(col.table()->name()) + ".";
}
result += d.prepare_identifier_string(col.name());
} else { } else {
result = d.sql_function_at(col.function()) + "(" + col.name() + ")"; result = d.sql_function_at(col.function()) + "(" + col.name() + ")";
} }

View File

@ -91,7 +91,7 @@ const table_column* table::operator[](const std::string &column_name) const {
const table_column * table::column_by_name(const table &tab, const std::string &column_name) { const table_column * table::column_by_name(const table &tab, const std::string &column_name) {
for (const auto &col : tab.columns_) { for (const auto &col : tab.columns_) {
if (col.name() == column_name) { if (col.column_name() == column_name) {
return &col; return &col;
} }
} }

View File

@ -25,42 +25,39 @@ table_column::table_column(const char *name)
: table_column(std::string(name)) : table_column(std::string(name))
{} {}
table_column::table_column(std::string name) table_column::table_column(const std::string& name)
: name_(std::move(name)) {} : table_column(name, name) {}
table_column::table_column(std::string name, std::string alias)
: name_(std::move(name))
, alias_(std::move(alias)) {}
table_column::table_column(const sql::sql_function_t func, std::string name) table_column::table_column(const std::string& name, const std::string& alias)
: name_(std::move(name)) : table_column(nullptr, name, alias, utils::basic_type::Unknown, {}, sql::sql_function_t::None)
, function_(func) {} {}
table_column::table_column(const class table* tab, std::string name) table_column::table_column(const sql::sql_function_t func, const std::string& name)
: table_(tab) : table_column(nullptr, name, name, utils::basic_type::Unknown, {}, func)
, name_(std::move(name)) {} {}
table_column::table_column(const class table* tab, const std::string& name)
: table_column(tab, name, name, utils::basic_type::Unknown, {}, sql::sql_function_t::None)
{}
table_column::table_column(const class table* tab, const std::string& name, const std::string& alias)
: table_column(tab, name, alias, utils::basic_type::Unknown, {}, sql::sql_function_t::None)
{}
table_column::table_column(const class table* tab, const std::string& name, const utils::basic_type type, const utils::field_attributes& attributes)
: table_column(tab, name, name, type, attributes, sql::sql_function_t::None)
{}
table_column::table_column(const class table* tab, std::string name, std::string alias)
: table_(tab)
, name_(std::move(name))
, alias_(std::move(alias)) {}
table_column::table_column(const class table* tab, table_column::table_column(const class table* tab,
std::string name, const std::string& name,
const std::string& alias,
const utils::basic_type type, const utils::basic_type type,
const utils::field_attributes& attributes)
: table_(tab)
, name_(std::move(name))
, type_(type)
, attributes_(attributes) {}
table_column::table_column(const class table* tab,
std::string name,
std::string alias,
utils::basic_type type,
const utils::field_attributes &attributes, const utils::field_attributes &attributes,
const sql::sql_function_t func) const sql::sql_function_t func)
: table_(tab) : table_(tab)
, name_(std::move(name)) , name_(build_column_name(table_, name))
, alias_(std::move(alias)) , column_name_(name)
, alias_(alias)
, type_(type) , type_(type)
, attributes_(attributes) , attributes_(attributes)
, function_(func) {} , function_(func) {}
@ -71,6 +68,7 @@ table_column & table_column::operator=(const table_column &other) {
} }
table_ = other.table_; table_ = other.table_;
name_ = other.name_; name_ = other.name_;
column_name_ = other.column_name_;
alias_ = other.alias_; alias_ = other.alias_;
type_ = other.type_; type_ = other.type_;
attributes_ = other.attributes_; attributes_ = other.attributes_;
@ -82,6 +80,7 @@ bool table_column::equals(const table_column &x) const {
if (table_ != nullptr && x.table_ != nullptr) { if (table_ != nullptr && x.table_ != nullptr) {
return *table_ == *x.table_ && return *table_ == *x.table_ &&
name_ == x.name_ && name_ == x.name_ &&
column_name_ == x.column_name_ &&
alias_ == x.alias_ && alias_ == x.alias_ &&
function_ == x.function_; function_ == x.function_;
} }
@ -92,15 +91,19 @@ bool table_column::equals(const table_column &x) const {
} }
table_column table_column::as(const std::string& alias) const { table_column table_column::as(const std::string& alias) const {
return {table_, name_, alias, type_, attributes_, function_}; return {table_, column_name_, alias, type_, attributes_, function_};
} }
const std::string& table_column::name() const { const std::string& table_column::name() const {
return name_; return has_alias() ? alias_ : name_;
} }
std::string table_column::canonical_name() const { const std::string& table_column::column_name() const {
return table_ ? table_->name() + "." + name_ : name_; return column_name_;
}
const std::string& table_column::canonical_name() const {
return name_;
} }
const std::string& table_column::alias() const { const std::string& table_column::alias() const {
@ -128,7 +131,7 @@ sql::sql_function_t table_column::function() const {
} }
bool table_column::has_alias() const { bool table_column::has_alias() const {
return !alias_.empty(); return alias_ != column_name_;
} }
const class table* table_column::table() const { const class table* table_column::table() const {
@ -137,9 +140,14 @@ const class table* table_column::table() const {
void table_column::table(const query::table* tab) { void table_column::table(const query::table* tab) {
table_ = tab; table_ = tab;
name_ = build_column_name(table_, column_name_);
} }
table_column::operator const std::string&() const { table_column::operator const std::string&() const {
return name_; return name();
} }
std::string table_column::build_column_name(const class query::table* tab, const std::string& name) {
return tab ? tab->name() + "." + name : name;
} }
} // namespace matador::query

View File

@ -18,16 +18,6 @@ const std::string &dialect::sql_function_at(const sql_function_t func) const {
return sql_func_map_.at(func); return sql_func_map_.at(func);
} }
std::string dialect::table_name(const std::string &table, const std::string &schema_name) const {
if (schema_name.empty() && default_schema_name_.empty()) {
return prepare_identifier_string(table);
}
if (schema_name.empty()) {
return prepare_identifier_string(default_schema_name_) + "." + prepare_identifier_string(table);
}
return prepare_identifier_string(schema_name) + "." + prepare_identifier_string(table);
}
const std::string &dialect::to_string(const bool val) const { const std::string &dialect::to_string(const bool val) const {
return bool_strings_[static_cast<int>(val)]; return bool_strings_[static_cast<int>(val)];
} }
@ -89,7 +79,7 @@ dialect::escape_identifier_t dialect::identifier_escape_type() const {
return identifier_escape_type_; return identifier_escape_type_;
} }
void dialect::identifier_escape_type(escape_identifier_t escape_identifier) { void dialect::identifier_escape_type(const escape_identifier_t escape_identifier) {
identifier_escape_type_ = escape_identifier; identifier_escape_type_ = escape_identifier;
} }

View File

@ -15,5 +15,7 @@ META_TABLE(departments, DEPARTMENT, id, name)
META_TABLE(employees, EMPLOYEE, id, first_name, last_name, dep_id) META_TABLE(employees, EMPLOYEE, id, first_name, last_name, dep_id)
META_TABLE(authors, AUTHOR, id, first_name, last_name, date_of_birth, year_of_birth, distinguished) META_TABLE(authors, AUTHOR, id, first_name, last_name, date_of_birth, year_of_birth, distinguished)
META_TABLE(books, BOOK, id, title, author_id, published_in) META_TABLE(books, BOOK, id, title, author_id, published_in)
META_TABLE(orders, ORDER, order_id, order_date, required_date, shipped_date, ship_via, freight, ship_name, ship_address, ship_city, ship_region, ship_postal_code, ship_country)
META_TABLE(courses, COURSE, id, title)
#endif //MATADOR_MODEL_METAS_HPP #endif //MATADOR_MODEL_METAS_HPP

View File

@ -24,12 +24,14 @@
#include "../../models/recipe.hpp" #include "../../models/recipe.hpp"
#include "../../models/order.hpp" #include "../../models/order.hpp"
#include "../../models/student.hpp" #include "../../models/student.hpp"
#include "../../models/model_metas.hpp"
using namespace matador::object; using namespace matador::object;
using namespace matador::query; using namespace matador::query;
using namespace matador::utils; using namespace matador::utils;
using namespace matador::sql; using namespace matador::sql;
using namespace matador::test; using namespace matador::test;
using namespace matador::query::meta;
TEST_CASE("Create sql query data for entity with eager has one", "[query][entity][builder]") { TEST_CASE("Create sql query data for entity with eager has one", "[query][entity][builder]") {
using namespace matador::test; using namespace matador::test;
@ -46,7 +48,7 @@ TEST_CASE("Create sql query data for entity with eager has one", "[query][entity
const auto it = scm.find(typeid(flight)); const auto it = scm.find(typeid(flight));
REQUIRE(it != scm.end()); REQUIRE(it != scm.end());
const auto* col = it->second.table()["id"]; const auto* col = it->second.table()[FLIGHT.id];
REQUIRE(col); REQUIRE(col);
auto data = eqb.build<flight>(*col == _); auto data = eqb.build<flight>(*col == _);
@ -100,7 +102,7 @@ TEST_CASE("Create sql query data for entity with eager belongs to", "[query][ent
const auto it = scm.find(typeid(book)); const auto it = scm.find(typeid(book));
REQUIRE(it != scm.end()); REQUIRE(it != scm.end());
const auto* col = it->second.table()["id"]; const auto* col = it->second.table()[BOOK.id];
REQUIRE(col); REQUIRE(col);
auto data = eqb.build<book>(*col == _); auto data = eqb.build<book>(*col == _);
@ -172,7 +174,7 @@ TEST_CASE("Create sql query data for entity with eager has many belongs to", "[q
const auto it = scm.find(typeid(order)); const auto it = scm.find(typeid(order));
REQUIRE(it != scm.end()); REQUIRE(it != scm.end());
const auto* col = it->second.table()["order_id"]; const auto* col = it->second.table()[ORDER.order_id];
REQUIRE(col); REQUIRE(col);
auto data = eqb.build<order>(*col == _); auto data = eqb.build<order>(*col == _);
@ -236,7 +238,7 @@ TEST_CASE("Create sql query data for entity with eager many to many", "[query][e
const auto it = scm.find(typeid(ingredient)); const auto it = scm.find(typeid(ingredient));
REQUIRE(it != scm.end()); REQUIRE(it != scm.end());
const auto* col = it->second.table()["id"]; const auto* col = it->second.table()[INGREDIENT.id];
REQUIRE(col); REQUIRE(col);
auto data = eqb.build<ingredient>(*col == _); auto data = eqb.build<ingredient>(*col == _);
@ -290,7 +292,7 @@ TEST_CASE("Create sql query data for entity with eager many to many (inverse par
const auto it = scm.find(typeid(course)); const auto it = scm.find(typeid(course));
REQUIRE(it != scm.end()); REQUIRE(it != scm.end());
const auto* col = it->second.table()["id"]; const auto* col = it->second.table()[COURSE.id];
REQUIRE(col); REQUIRE(col);
auto data = eqb.build<course>(*col == _); auto data = eqb.build<course>(*col == _);

View File

@ -47,7 +47,7 @@ TEST_CASE("Generate columns from object", "[column][generator]") {
REQUIRE(columns.size() == expected_columns.size()); REQUIRE(columns.size() == expected_columns.size());
for (size_t i = 0; i != expected_columns.size(); ++i) { for (size_t i = 0; i != expected_columns.size(); ++i) {
REQUIRE(expected_columns[i] == columns[i].name()); REQUIRE(expected_columns[i] == columns[i].column_name());
} }
} }

View File

@ -2,9 +2,9 @@
#include "matador/query/criteria.hpp" #include "matador/query/criteria.hpp"
#include "matador/query/criteria_evaluator.hpp" #include "matador/query/criteria_evaluator.hpp"
#include "matador/query/query.hpp"
#include "matador/sql/dialect_builder.hpp" #include "matador/sql/dialect_builder.hpp"
#include "matador/sql/query_context.hpp"
#include "matador/utils/placeholder.hpp" #include "matador/utils/placeholder.hpp"
@ -79,7 +79,9 @@ TEST_CASE_METHOD(CriteriaFixture, "Test in query criteria", "[criteria][in query
query_context sub_ctx; query_context sub_ctx;
sub_ctx.sql = R"(SELECT "name" FROM "test")"; sub_ctx.sql = R"(SELECT "name" FROM "test")";
auto clause = age_col != 7 && in(name_col, std::move(sub_ctx)); auto q = query::select({name_col}).from("test");
auto clause = age_col != 7 && in(name_col, std::move(q));
} }
TEST_CASE_METHOD(CriteriaFixture, "Test out criteria", "[criteria][out]") { TEST_CASE_METHOD(CriteriaFixture, "Test out criteria", "[criteria][out]") {
const auto age_col = "age"_col; const auto age_col = "age"_col;
@ -88,12 +90,12 @@ TEST_CASE_METHOD(CriteriaFixture, "Test out criteria", "[criteria][out]") {
criteria_evaluator evaluator(dlc, ctx); criteria_evaluator evaluator(dlc, ctx);
auto str = evaluator.evaluate(*clause); auto str = evaluator.evaluate(*clause);
REQUIRE(str == "(\"age\" <> 7 AND \"age\" NOT IN (7, 5, 5, 8))"); REQUIRE(str == R"(("age" <> 7 AND "age" NOT IN (7, 5, 5, 8)))");
clause = age_col != 7 && out(age_col, {_, _, _}); clause = age_col != 7 && out(age_col, {_, _, _});
str = evaluator.evaluate(*clause); str = evaluator.evaluate(*clause);
REQUIRE(str == "(\"age\" <> 7 AND \"age\" NOT IN (?, ?, ?))"); REQUIRE(str == R"(("age" <> 7 AND "age" NOT IN (?, ?, ?)))");
} }
TEST_CASE_METHOD(CriteriaFixture, "Test between criteria", "[criteria][between]") { TEST_CASE_METHOD(CriteriaFixture, "Test between criteria", "[criteria][between]") {
@ -103,12 +105,12 @@ TEST_CASE_METHOD(CriteriaFixture, "Test between criteria", "[criteria][between]"
criteria_evaluator evaluator(dlc, ctx); criteria_evaluator evaluator(dlc, ctx);
auto str = evaluator.evaluate(*clause); auto str = evaluator.evaluate(*clause);
REQUIRE(str == "(\"age\" <> 7 OR \"age\" BETWEEN 21 AND 30)"); REQUIRE(str == R"(("age" <> 7 OR "age" BETWEEN 21 AND 30))");
clause = age_col != 7 || between(age_col, _, _); clause = age_col != 7 || between(age_col, _, _);
str = evaluator.evaluate(*clause); str = evaluator.evaluate(*clause);
REQUIRE(str == "(\"age\" <> 7 OR \"age\" BETWEEN ? AND ?)"); REQUIRE(str == R"(("age" <> 7 OR "age" BETWEEN ? AND ?))");
} }
TEST_CASE_METHOD(CriteriaFixture, "Test like criteria", "[criteria][like]") { TEST_CASE_METHOD(CriteriaFixture, "Test like criteria", "[criteria][like]") {

View File

@ -7,7 +7,7 @@
using namespace matador::query; using namespace matador::query;
using namespace matador::test; using namespace matador::test;
TEST_CASE("Test schema with belongs-to to has-many relation" "[schema][relation][belongs_to]") { TEST_CASE("Test schema with belongs-to to has-many relation" "[schema][relation][belongsto]") {
schema repo; schema repo;
auto result = repo.attach<package>("packages") auto result = repo.attach<package>("packages")
.and_then( [&repo] { return repo.attach<shipment>("shipments"); } ); .and_then( [&repo] { return repo.attach<shipment>("shipments"); } );