entity query and record progress

This commit is contained in:
Sascha Kuehl 2024-03-04 20:09:39 +01:00
parent 830185c3c5
commit be610ffcad
31 changed files with 294 additions and 50 deletions

View File

@ -37,7 +37,7 @@ public:
size_t execute(const std::string &stmt) override; size_t execute(const std::string &stmt) override;
sql::record describe(const std::string& table) override; std::vector<sql::column_definition> describe(const std::string& table) override;
bool exists(const std::string &schema_name, const std::string &table_name) override; bool exists(const std::string &schema_name, const std::string &table_name) override;

View File

@ -181,13 +181,13 @@ std::unique_ptr<sql::query_result_impl> mysql_connection::fetch(const std::strin
auto field_count = mysql_num_fields(result); auto field_count = mysql_num_fields(result);
auto fields = mysql_fetch_fields(result); auto fields = mysql_fetch_fields(result);
sql::record prototype; std::vector<sql::column_definition> prototype;
for (unsigned i = 0; i < field_count; ++i) { for (unsigned i = 0; i < field_count; ++i) {
auto type = to_type(fields[i].type, fields[i].flags); auto type = to_type(fields[i].type, fields[i].flags);
auto options = to_constraints(fields[i].flags); auto options = to_constraints(fields[i].flags);
auto null_opt = to_null_option(fields[i].flags); auto null_opt = to_null_option(fields[i].flags);
prototype.append({fields[i].name, type, options, null_opt}); prototype.emplace_back(fields[i].name, type, options, null_opt);
} }
return std::move(std::make_unique<sql::query_result_impl>(std::make_unique<mysql_result_reader>(result, field_count), std::move(prototype))); return std::move(std::make_unique<sql::query_result_impl>(std::make_unique<mysql_result_reader>(result, field_count), std::move(prototype)));
@ -216,7 +216,7 @@ size_t mysql_connection::execute(const std::string &stmt)
return mysql_affected_rows(mysql_.get()); return mysql_affected_rows(mysql_.get());
} }
sql::record mysql_connection::describe(const std::string &table) std::vector<sql::column_definition> mysql_connection::describe(const std::string &table)
{ {
std::string stmt("SHOW COLUMNS FROM " + table); std::string stmt("SHOW COLUMNS FROM " + table);
@ -230,7 +230,7 @@ sql::record mysql_connection::describe(const std::string &table)
} }
mysql_result_reader reader(result, mysql_num_fields(result)); mysql_result_reader reader(result, mysql_num_fields(result));
sql::record prototype; std::vector<sql::column_definition> prototype;
while (reader.fetch()) { while (reader.fetch()) {
char *end = nullptr; char *end = nullptr;
@ -242,7 +242,7 @@ sql::record mysql_connection::describe(const std::string &table)
if (strtoul(reader.column(2), &end, 10) == 0) { if (strtoul(reader.column(2), &end, 10) == 0) {
null_opt = sql::null_option::NOT_NULL; null_opt = sql::null_option::NOT_NULL;
} }
prototype.append({name, typeinfo.type, {typeinfo.size}, null_opt, prototype.size()}); prototype.push_back({name, typeinfo.type, {typeinfo.size}, null_opt, prototype.size()});
} }
return prototype; return prototype;

View File

@ -33,7 +33,7 @@ public:
size_t execute(const std::string &stmt) override; size_t execute(const std::string &stmt) override;
sql::record describe(const std::string& table) override; std::vector<sql::column_definition> describe(const std::string& table) override;
bool exists(const std::string &schema_name, const std::string &table_name) override; bool exists(const std::string &schema_name, const std::string &table_name) override;

View File

@ -51,14 +51,13 @@ std::unique_ptr<sql::query_result_impl> postgres_connection::fetch(const std::st
throw_postgres_error(res, conn_, "postgres", stmt); throw_postgres_error(res, conn_, "postgres", stmt);
sql::record prototype; std::vector<sql::column_definition> prototype;
auto num_col = PQnfields(res); auto num_col = PQnfields(res);
for (int i = 0; i < num_col; ++i) { for (int i = 0; i < num_col; ++i) {
const char *col_name = PQfname(res, i); const char *col_name = PQfname(res, i);
auto type = PQftype(res, i); auto type = PQftype(res, i);
auto size = PQfmod(res, i); auto size = PQfmod(res, i);
// std::cout << "column " << col_name << ", type " << type << " (size: " << size << ")\n"; prototype.emplace_back(col_name);
prototype.append(sql::column_definition{col_name});
} }
return std::move(std::make_unique<sql::query_result_impl>(std::make_unique<postgres_result_reader>(res), std::move(prototype))); return std::move(std::make_unique<sql::query_result_impl>(std::make_unique<postgres_result_reader>(res), std::move(prototype)));
} }
@ -131,7 +130,7 @@ sql::data_type_t string2type(const char *type)
} }
} }
sql::record postgres_connection::describe(const std::string &table) std::vector<sql::column_definition> postgres_connection::describe(const std::string &table)
{ {
std::string stmt( std::string stmt(
"SELECT ordinal_position, column_name, udt_name, data_type, is_nullable, column_default FROM information_schema.columns WHERE table_schema='public' AND table_name='" + table + "'"); "SELECT ordinal_position, column_name, udt_name, data_type, is_nullable, column_default FROM information_schema.columns WHERE table_schema='public' AND table_name='" + table + "'");
@ -141,7 +140,7 @@ sql::record postgres_connection::describe(const std::string &table)
throw_postgres_error(res, conn_, "postgres", stmt); throw_postgres_error(res, conn_, "postgres", stmt);
postgres_result_reader reader(res); postgres_result_reader reader(res);
sql::record prototype; std::vector<sql::column_definition> prototype;
while (reader.fetch()) { while (reader.fetch()) {
char *end = nullptr; char *end = nullptr;
// Todo: Handle error // Todo: Handle error
@ -156,7 +155,7 @@ sql::record postgres_connection::describe(const std::string &table)
null_opt = sql::null_option::NOT_NULL; null_opt = sql::null_option::NOT_NULL;
} }
// f.default_value(res->column(4)); // f.default_value(res->column(4));
prototype.append({name, type, utils::null_attributes, null_opt, index}); prototype.emplace_back(name, type, utils::null_attributes, null_opt, index);
} }
return std::move(prototype); return std::move(prototype);

View File

@ -33,14 +33,14 @@ public:
size_t execute(const std::string &stmt) override; size_t execute(const std::string &stmt) override;
sql::record describe(const std::string& table) override; std::vector<sql::column_definition> describe(const std::string& table) override;
bool exists(const std::string &schema_name, const std::string &table_name) override; bool exists(const std::string &schema_name, const std::string &table_name) override;
private: private:
struct fetch_context struct fetch_context
{ {
sql::record prototype; std::vector<sql::column_definition> prototype;
sqlite_result_reader::rows rows; sqlite_result_reader::rows rows;
}; };

View File

@ -65,7 +65,7 @@ int sqlite_connection::parse_result(void* param, int column_count, char** values
if (context->prototype.empty()) { if (context->prototype.empty()) {
for(int i = 0; i < column_count; ++i) { for(int i = 0; i < column_count; ++i) {
context->prototype.append(sql::column_definition{columns[i]}); context->prototype.emplace_back(columns[i]);
} }
} }
@ -144,12 +144,12 @@ sql::data_type_t string2type(const char *type)
} }
} }
sql::record sqlite_connection::describe(const std::string& table) std::vector<sql::column_definition> sqlite_connection::describe(const std::string& table)
{ {
const auto result = fetch_internal("PRAGMA table_info(" + table + ")"); const auto result = fetch_internal("PRAGMA table_info(" + table + ")");
sqlite_result_reader reader(result.rows, result.prototype.size()); sqlite_result_reader reader(result.rows, result.prototype.size());
sql::record prototype; std::vector<sql::column_definition> prototype;
while (reader.fetch()) { while (reader.fetch()) {
char *end = nullptr; char *end = nullptr;
// Todo: add index to column // Todo: add index to column
@ -163,7 +163,7 @@ sql::record sqlite_connection::describe(const std::string& table)
null_opt = sql::null_option::NOT_NULL; null_opt = sql::null_option::NOT_NULL;
} }
// f.default_value(res->column(4)); // f.default_value(res->column(4));
prototype.append({name, type, utils::null_attributes, null_opt, index}); prototype.emplace_back(name, type, utils::null_attributes, null_opt, index);
} }
return std::move(prototype); return std::move(prototype);

View File

@ -37,10 +37,19 @@ private:
using namespace matador; using namespace matador;
TEST_CASE_METHOD(SessionFixture, "Session relation test", "[session][relation]") { TEST_CASE_METHOD(SessionFixture, "Session relation test", "[session][relation]") {
using namespace matador;
ses.attach<matador::test::airplane>("airplane"); ses.attach<test::airplane>("airplane");
ses.create_schema(); ses.create_schema();
ses.insert<test::airplane>(1, "Boeing", "A380"); ses.insert<test::airplane>(1, "Boeing", "A380");
REQUIRE(true); REQUIRE(true);
} }
TEST_CASE_METHOD(SessionFixture, "Find object with id", "[session][find]") {
ses.attach<matador::test::airplane>("airplane");
ses.create_schema();
auto a380 = ses.insert<test::airplane>(1, "Boeing", "A380");
ses.find<test::airplane>(1);
}

View File

@ -10,6 +10,17 @@
namespace matador::sql { namespace matador::sql {
using any_db_type = std::variant<
long long,
unsigned long long,
double,
bool,
const char*,
std::string,
utils::blob,
placeholder,
nullptr_t>;
using any_type = std::variant< using any_type = std::variant<
char, short, int, long, long long, char, short, int, long, long long,
unsigned char, unsigned short, unsigned int, unsigned long, unsigned long long, unsigned char, unsigned short, unsigned int, unsigned long, unsigned long long,

View File

@ -9,7 +9,6 @@
#include "matador/sql/query_result.hpp" #include "matador/sql/query_result.hpp"
#include "matador/sql/record.hpp" #include "matador/sql/record.hpp"
#include "matador/sql/statement.hpp" #include "matador/sql/statement.hpp"
#include "matador/sql/schema.hpp"
#include "matador/utils/logger.hpp" #include "matador/utils/logger.hpp"
@ -17,6 +16,8 @@
namespace matador::sql { namespace matador::sql {
class schema;
class connection class connection
{ {
public: public:
@ -32,7 +33,7 @@ public:
[[nodiscard]] bool is_open() const; [[nodiscard]] bool is_open() const;
[[nodiscard]] const connection_info& info() const; [[nodiscard]] const connection_info& info() const;
[[nodiscard]] record describe(const std::string &table_name) const; [[nodiscard]] std::vector<sql::column_definition> describe(const std::string &table_name) const;
[[nodiscard]] bool exists(const std::string &schema_name, const std::string &table_name) const; [[nodiscard]] bool exists(const std::string &schema_name, const std::string &table_name) const;
[[nodiscard]] bool exists(const std::string &table_name) const; [[nodiscard]] bool exists(const std::string &table_name) const;

View File

@ -26,7 +26,7 @@ public:
virtual std::unique_ptr<query_result_impl> fetch(const std::string &stmt) = 0; virtual std::unique_ptr<query_result_impl> fetch(const std::string &stmt) = 0;
virtual std::unique_ptr<statement_impl> prepare(query_context context) = 0; virtual std::unique_ptr<statement_impl> prepare(query_context context) = 0;
virtual record describe(const std::string &table) = 0; virtual std::vector<sql::column_definition> describe(const std::string &table) = 0;
virtual bool exists(const std::string &schema_name, const std::string &table_name) = 0; virtual bool exists(const std::string &schema_name, const std::string &table_name) = 0;
protected: protected:

View File

@ -0,0 +1,62 @@
#ifndef QUERY_ENTITY_QUERY_BUILDER_HPP
#define QUERY_ENTITY_QUERY_BUILDER_HPP
#include "matador/sql/query_context.hpp"
namespace matador::sql {
template < typename PrimaryKeyType >
class entity_query_builder
{
public:
// determine pk
// collect eager relations for joins
template<class EntityType>
query_context build() {
EntityType obj;
matador::utils::access::process(*this, obj);
return {};
}
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)
{
}
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) {}
template<class Pointer>
void on_belongs_to(const char *id, Pointer &, const utils::foreign_attributes &/*attr*/)
{
}
template<class Pointer>
void on_has_one(const char *id, Pointer &, 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 *id, ContainerType &c, const utils::foreign_attributes &attr)
{
on_has_many(id, c, "", "", attr);
}
private:
PrimaryKeyType pk_;
};
}
#endif //QUERY_ENTITY_QUERY_BUILDER_HPP

View File

@ -0,0 +1,37 @@
#ifndef QUERY_FIELD_HPP
#define QUERY_FIELD_HPP
#include "matador/sql/any_type.hpp"
#include "matador/sql/any_type_to_visitor.hpp"
#include <string>
namespace matador::sql {
class field
{
public:
[[nodiscard]] const std::string& name() const;
template<class Type>
Type as() const
{
const Type* ptr= std::get_if<Type>(&value_);
if (ptr) {
return *ptr;
}
any_type_to_visitor<Type> visitor;
std::visit(visitor, const_cast<any_type&>(value_));
return visitor.result;
}
friend std::ostream& operator<<(std::ostream &out, const field &col);
private:
std::string name_;
any_type value_;
};
}
#endif //QUERY_FIELD_HPP

View File

@ -16,7 +16,7 @@ public:
size_t execute(const std::string &stmt) override; size_t execute(const std::string &stmt) override;
std::unique_ptr<query_result_impl> fetch(const std::string &stmt) override; std::unique_ptr<query_result_impl> fetch(const std::string &stmt) override;
std::unique_ptr<statement_impl> prepare(query_context context) override; std::unique_ptr<statement_impl> prepare(query_context context) override;
record describe(const std::string &table) override; std::vector<sql::column_definition> describe(const std::string &table) override;
bool exists(const std::string &schema_name, const std::string &table_name) override; bool exists(const std::string &schema_name, const std::string &table_name) override;
private: private:

View File

@ -11,7 +11,7 @@ struct query_context
std::string sql; std::string sql;
std::string command_name; std::string command_name;
sql::table table{""}; sql::table table{""};
record prototype; std::vector<column_definition> prototype;
std::vector<std::string> result_vars; std::vector<std::string> result_vars;
std::vector<std::string> bind_vars; std::vector<std::string> bind_vars;
}; };

View File

@ -107,13 +107,13 @@ private:
namespace detail { namespace detail {
template < typename Type > template < typename Type >
Type* create_prototype(const record &/*prototype*/) Type* create_prototype(const std::vector<column_definition> &/*prototype*/)
{ {
return new Type{}; return new Type{};
} }
template <> template <>
record* create_prototype<record>(const record &prototype); record* create_prototype<record>(const std::vector<column_definition> &prototype);
} }
@ -128,7 +128,7 @@ public:
explicit query_result(std::unique_ptr<query_result_impl> impl) explicit query_result(std::unique_ptr<query_result_impl> impl)
: impl_(std::move(impl)) {} : impl_(std::move(impl)) {}
query_result(std::unique_ptr<query_result_impl> impl, record record_prototype) query_result(std::unique_ptr<query_result_impl> impl, std::vector<column_definition> record_prototype)
: record_prototype_(std::move(record_prototype)) : record_prototype_(std::move(record_prototype))
, impl_(std::move(impl)) {} , impl_(std::move(impl)) {}
@ -151,7 +151,7 @@ private:
} }
private: private:
record record_prototype_; std::vector<column_definition> record_prototype_;
std::unique_ptr<query_result_impl> impl_; std::unique_ptr<query_result_impl> impl_;
}; };

View File

@ -55,7 +55,7 @@ private:
class query_result_impl class query_result_impl
{ {
public: public:
query_result_impl(std::unique_ptr<query_result_reader> &&reader, record prototype); query_result_impl(std::unique_ptr<query_result_reader> &&reader, std::vector<column_definition> prototype);
template<typename ValueType> template<typename ValueType>
void on_primary_key(const char *id, ValueType &value, typename std::enable_if<std::is_integral<ValueType>::value && !std::is_same<bool, ValueType>::value>::type* = 0) void on_primary_key(const char *id, ValueType &value, typename std::enable_if<std::is_integral<ValueType>::value && !std::is_same<bool, ValueType>::value>::type* = 0)
@ -110,11 +110,11 @@ public:
return true; return true;
} }
[[nodiscard]] const record& prototype() const; [[nodiscard]] const std::vector<column_definition>& prototype() const;
protected: protected:
size_t column_index_ = 0; size_t column_index_ = 0;
record prototype_; std::vector<column_definition> prototype_;
std::unique_ptr<query_result_reader> reader_; std::unique_ptr<query_result_reader> reader_;
detail::pk_reader pk_reader_; detail::pk_reader pk_reader_;
}; };

View File

@ -31,6 +31,28 @@ public:
return insert(new Type(std::forward<Args>(args)...)); return insert(new Type(std::forward<Args>(args)...));
} }
template<typename Type, typename PrimaryKeyType>
entity<Type> find(const PrimaryKeyType &pk) {
auto c = pool_.acquire();
if (!c.valid()) {
throw std::logic_error("no database connection available");
}
// collect all columns
// - evaluate fetch::Eager flag for relations
// build pk where condition
// - check if type has pk
// - check type
// pk_condition_builder<Type> builder;
// auto cond = builder.build(pk);
// create query with relations as requested
//
// c->query(*schema_).select<Type>().from("xyz").where().fetch_all();
return {};
}
template<typename Type> template<typename Type>
void drop_table(); void drop_table();
void drop_table(const std::string &table_name); void drop_table(const std::string &table_name);
@ -40,7 +62,7 @@ public:
[[nodiscard]] size_t execute(const std::string &sql) const; [[nodiscard]] size_t execute(const std::string &sql) const;
statement prepare(query_context q) const; statement prepare(query_context q) const;
record describe_table(const std::string &table_name) const; std::vector<sql::column_definition> describe_table(const std::string &table_name) const;
bool table_exists(const std::string &table_name) const; bool table_exists(const std::string &table_name) const;
[[nodiscard]] const schema& tables() const; [[nodiscard]] const schema& tables() const;

View File

@ -35,6 +35,7 @@ set(SQL_SOURCES
sql/noop_connection.cpp sql/noop_connection.cpp
sql/query_part.cpp sql/query_part.cpp
sql/any_type_to_string_visitor.cpp sql/any_type_to_string_visitor.cpp
sql/field.cpp
) )
set(SQL_HEADER set(SQL_HEADER
@ -86,6 +87,8 @@ set(SQL_HEADER
../include/matador/sql/query_part.hpp ../include/matador/sql/query_part.hpp
../include/matador/sql/any_type_to_string_visitor.hpp ../include/matador/sql/any_type_to_string_visitor.hpp
../include/matador/sql/query_helper.hpp ../include/matador/sql/query_helper.hpp
../include/matador/sql/field.hpp
../include/matador/sql/entity_query_builder.hpp
) )
set(QUERY_SOURCES set(QUERY_SOURCES

View File

@ -2,7 +2,9 @@
#include "matador/sql/backend_provider.hpp" #include "matador/sql/backend_provider.hpp"
#include "matador/sql/connection_impl.hpp" #include "matador/sql/connection_impl.hpp"
#include "matador/sql/schema.hpp"
#include <algorithm>
#include <stdexcept> #include <stdexcept>
#include <utility> #include <utility>
@ -68,7 +70,7 @@ const connection_info &connection::info() const
return connection_info_; return connection_info_;
} }
record connection::describe(const std::string &table_name) const std::vector<sql::column_definition> connection::describe(const std::string &table_name) const
{ {
return std::move(connection_->describe(table_name)); return std::move(connection_->describe(table_name));
} }
@ -94,12 +96,21 @@ sql::query connection::query(const sql::schema &schema) const
return sql::query(*const_cast<connection*>(this), schema); return sql::query(*const_cast<connection*>(this), schema);
} }
bool is_unknown(const std::vector<sql::column_definition> &columns) {
return std::all_of(std::begin(columns), std::end(columns), [](const auto &col) {
return col.type() == data_type_t::type_unknown;
});
}
query_result<record> connection::fetch(const query_context &q) const query_result<record> connection::fetch(const query_context &q) const
{ {
if (q.prototype.empty() || q.prototype.unknown()) { if (q.prototype.empty() || is_unknown(q.prototype)) {
const auto table_prototype = describe(q.table.name); const auto table_prototype = describe(q.table.name);
for (auto &col : q.prototype) { for (auto &col : q.prototype) {
if (const auto rit = table_prototype.find(col.name()); col.type() == data_type_t::type_unknown && rit != table_prototype.end()) { const auto rit = std::find_if(std::begin(table_prototype), std::end(table_prototype), [&col](const auto &value) {
return value.name() == col.name();
});
if (col.type() == data_type_t::type_unknown && rit != table_prototype.end()) {
const_cast<column_definition&>(col).type(rit->type()); const_cast<column_definition&>(col).type(rit->type());
} }
} }

15
src/sql/field.cpp Normal file
View File

@ -0,0 +1,15 @@
#include "matador/sql/field.hpp"
namespace matador::sql {
const std::string &field::name() const
{
return name_;
}
std::ostream &operator<<(std::ostream &out, const field &col)
{
return out;
}
}

View File

@ -39,7 +39,7 @@ std::unique_ptr<statement_impl> noop_connection::prepare(query_context context)
return {}; return {};
} }
record noop_connection::describe(const std::string &table) std::vector<sql::column_definition> noop_connection::describe(const std::string &table)
{ {
return {}; return {};
} }

View File

@ -141,18 +141,18 @@ query_builder &query_builder::select(const std::vector<column> &columns)
for (const auto &col: columns) { for (const auto &col: columns) {
result.append(dialect_.prepare_identifier(col)); result.append(dialect_.prepare_identifier(col));
query_.result_vars.emplace_back(col.name); query_.result_vars.emplace_back(col.name);
query_.prototype.append(column_definition{col.name}); query_.prototype.emplace_back(col.name);
} }
} else { } else {
auto it = columns.begin(); auto it = columns.begin();
result.append(dialect_.prepare_identifier(*it)); result.append(dialect_.prepare_identifier(*it));
query_.result_vars.emplace_back(it->name); query_.result_vars.emplace_back(it->name);
query_.prototype.append(column_definition{(*it++).name}); query_.prototype.emplace_back((*it++).name);
for (; it != columns.end(); ++it) { for (; it != columns.end(); ++it) {
result.append(", "); result.append(", ");
result.append(dialect_.prepare_identifier(*it)); result.append(dialect_.prepare_identifier(*it));
query_.result_vars.emplace_back(it->name); query_.result_vars.emplace_back(it->name);
query_.prototype.append(column_definition{(*it).name}); query_.prototype.emplace_back((*it).name);
} }
} }

View File

@ -33,18 +33,18 @@ void query_compiler::visit(query_select_part &select_part)
for (const auto &col: columns) { for (const auto &col: columns) {
result.append(dialect_.prepare_identifier(col)); result.append(dialect_.prepare_identifier(col));
query_.result_vars.emplace_back(col.name); query_.result_vars.emplace_back(col.name);
query_.prototype.append(column_definition{col.name}); query_.prototype.emplace_back(col.name);
} }
} else { } else {
auto it = columns.begin(); auto it = columns.begin();
result.append(dialect_.prepare_identifier(*it)); result.append(dialect_.prepare_identifier(*it));
query_.result_vars.emplace_back(it->name); query_.result_vars.emplace_back(it->name);
query_.prototype.append(column_definition{(*it++).name}); query_.prototype.emplace_back((*it++).name);
for (; it != columns.end(); ++it) { for (; it != columns.end(); ++it) {
result.append(", "); result.append(", ");
result.append(dialect_.prepare_identifier(*it)); result.append(dialect_.prepare_identifier(*it));
query_.result_vars.emplace_back(it->name); query_.result_vars.emplace_back(it->name);
query_.prototype.append(column_definition{(*it).name}); query_.prototype.emplace_back((*it).name);
} }
} }

View File

@ -3,7 +3,7 @@
namespace matador::sql::detail { namespace matador::sql::detail {
template<> template<>
record *create_prototype<record>(const record &prototype) record *create_prototype<record>(const std::vector<column_definition> &prototype)
{ {
return new record{prototype}; return new record{prototype};
} }

View File

@ -11,7 +11,7 @@ void detail::pk_reader::on_primary_key(const char *id, std::string &value, size_
data_type_traits<std::string>::read_value(reader_, id, column_index_++, value, size); data_type_traits<std::string>::read_value(reader_, id, column_index_++, value, size);
} }
query_result_impl::query_result_impl(std::unique_ptr<query_result_reader> &&reader, record prototype) query_result_impl::query_result_impl(std::unique_ptr<query_result_reader> &&reader, std::vector<column_definition> prototype)
: prototype_(std::move(prototype)) : prototype_(std::move(prototype))
, reader_(std::move(reader)) , reader_(std::move(reader))
, pk_reader_(*reader_) , pk_reader_(*reader_)
@ -44,7 +44,7 @@ query_result_impl::on_attribute(const char *id, any_type &value, data_type_t typ
reader_->read_value(id, column_index_++, value, type, attr.size()); reader_->read_value(id, column_index_++, value, type, attr.size());
} }
const record& query_result_impl::prototype() const const std::vector<column_definition>& query_result_impl::prototype() const
{ {
return prototype_; return prototype_;
} }

View File

@ -71,7 +71,7 @@ statement session::prepare(query_context q) const
return c->prepare(std::move(q)); return c->prepare(std::move(q));
} }
record session::describe_table(const std::string &table_name) const std::vector<sql::column_definition> session::describe_table(const std::string &table_name) const
{ {
auto c = pool_.acquire(); auto c = pool_.acquire();
if (!c.valid()) { if (!c.valid()) {

View File

@ -35,7 +35,10 @@ add_executable(tests
models/optional.hpp models/optional.hpp
ConvertTest.cpp ConvertTest.cpp
DummyConnection.hpp DummyConnection.hpp
DummyConnection.cpp) DummyConnection.cpp
EntityQueryBuilderTest.cpp
models/author.hpp
models/book.hpp)
target_link_libraries(tests PRIVATE target_link_libraries(tests PRIVATE
Catch2::Catch2WithMain Catch2::Catch2WithMain

View File

@ -0,0 +1,11 @@
#include <catch2/catch_test_macros.hpp>
#include <matador/sql/connection.hpp>
using namespace matador::sql;
TEST_CASE("Create sql query for entity", "[query][entity][builder]") {
connection noop("noop://noop.db");
schema scm("noop");
}

View File

@ -4,7 +4,6 @@
#include <matador/sql/condition.hpp> #include <matador/sql/condition.hpp>
#include <matador/sql/connection.hpp> #include <matador/sql/connection.hpp>
#include <matador/sql/dialect_builder.hpp> #include <matador/sql/dialect_builder.hpp>
#include <matador/sql/query_builder.hpp>
#include <matador/sql/query.hpp> #include <matador/sql/query.hpp>
using namespace matador::sql; using namespace matador::sql;

27
test/models/author.hpp Normal file
View File

@ -0,0 +1,27 @@
#ifndef QUERY_AUTHOR_HPP
#define QUERY_AUTHOR_HPP
#include "matador/utils/access.hpp"
#include <string>
namespace matador::test {
struct category
{
unsigned long id{};
std::string name;
template<class Operator>
void process(Operator &op)
{
namespace field = matador::utils::access;
using namespace matador::utils;
field::primary_key(op, "id", id);
field::attribute(op, "name", name, 255);
}
};
}
#endif //QUERY_AUTHOR_HPP

34
test/models/book.hpp Normal file
View File

@ -0,0 +1,34 @@
#ifndef QUERY_BOOK_HPP
#define QUERY_BOOK_HPP
#include "matador/sql/entity.hpp"
#include "matador/utils/access.hpp"
#include "matador/utils/foreign_attributes.hpp"
#include <string>
namespace matador::test {
struct author;
struct book
{
unsigned long id{};
matador::sql::entity<author> book_author;
std::string title;
unsigned short published_in{};
template<typename Operator>
void process(Operator &op)
{
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::attribute(op, "published_in", published_in);
}
};
}
#endif //QUERY_BOOK_HPP