session progress

This commit is contained in:
2026-04-26 15:50:11 +02:00
parent 656d045ccf
commit 75d5cba6c3
25 changed files with 191 additions and 175 deletions
+5 -1
View File
@@ -135,7 +135,11 @@ private:
template<typename ValueType>
void object_generator::on_primary_key(const char *id, ValueType &x, const utils::primary_key_attribute& attr) {
auto &ref = emplace_attribute<ValueType>(id, { attr.size(), utils::constraints::PrimaryKey }, null_option_type::NotNull);
utils::constraints cs = utils::constraints::PrimaryKey;
if (attr.generator() == utils::generator_type::Identity) {
cs |= utils::constraints::Identity;
}
auto &ref = emplace_attribute<ValueType>(id, { attr.size(), cs }, null_option_type::NotNull);
prepare_primary_key(ref, utils::identifier(x));
}
+3 -1
View File
@@ -89,11 +89,13 @@ public:
[[nodiscard]] bool contains(const std::type_index &index) const;
const std::unordered_map<std::type_index, std::unique_ptr<sql::object_resolver_producer>>& resolver_producers() const;
const std::unordered_map<object::collection_composite_key, std::unique_ptr<sql::collection_resolver_producer>, object::collection_composite_key_hash>& collection_resolver_producers() const;
protected:
template<typename Type>
friend class schema_observer;
friend class producer_creator;
friend class producer_accessor;
object::repository repo_;
std::unordered_map<std::type_index, schema_node> schema_nodes_;
+1
View File
@@ -14,6 +14,7 @@ enum class error_code {
InvalidColumn,
InvalidConstraint,
InvalidDataType,
InvalidObject,
InvalidValue,
InvalidRelationType,
MissingPrimaryKey,
+21 -14
View File
@@ -86,8 +86,11 @@ public:
visited_.clear();
ptr_ = ptr;
build_for(ptr, steps_);
const auto result = build_for(ptr, steps_);
ptr_.reset();
if (!result) {
return utils::failure(result.err());
}
// relation inserts must run after all entity inserts were collected
for (auto &s : relation_steps_) {
@@ -151,8 +154,7 @@ public:
throw query_builder_exception(error_code::UnknownType, "Unknown type");
}
using relation_value_type = object::many_to_many_relation<ForeignType, ObjectType>;
using relation_value_type = object::many_to_many_relation<ObjectType, ForeignType>;
if (std::type_index(typeid(relation_value_type)) != it->second.node().info().type_index()) {
throw query_builder_exception(error_code::InvalidRelationType, "Invalid relation type");
}
@@ -162,7 +164,7 @@ public:
throw query_builder_exception(error_code::UnknownType, "Unknown type");
}
const auto rel_it = processing_many_to_many_relations_.insert(id);
std::ignore = processing_many_to_many_relations_.insert(id);
std::vector<insert_step> rel_steps;
for (auto &obj : objects) {
if (!obj) {
@@ -174,7 +176,7 @@ public:
build_for(obj, relation_steps_);
}
auto rel = object::make_object<relation_value_type>(join_column, inverse_join_column, obj, ptr_);
auto rel = object::make_object<relation_value_type>(join_column, inverse_join_column, ptr_, obj);
access::process(*this, *rel);
@@ -219,7 +221,7 @@ public:
throw query_builder_exception(error_code::UnknownType, "Unknown type");
}
const auto rel_it = processing_many_to_many_relations_.insert(id);
std::ignore = processing_many_to_many_relations_.insert(id);
std::vector<insert_step> rel_steps;
for (auto &obj : objects) {
if (!obj) {
@@ -263,24 +265,28 @@ private:
};
template<class EntityType>
void build_for(const object::object_ptr<EntityType> &ptr, std::vector<insert_step> &steps) {
utils::result<void, utils::error> build_for(const object::object_ptr<EntityType> &ptr, std::vector<insert_step> &steps) {
if (!ptr) {
return;
return utils::failure(utils::error{error_code::InvalidObject, "Object is null"});
}
const auto key = make_visit_key<EntityType>(ptr);
if (visited_.find(key) != visited_.end()) {
return;
return utils::ok<void>();
}
visited_.insert(key);
const auto it = schema_.find(typeid(EntityType));
if (it == schema_.end()) {
throw query_builder_exception(error_code::UnknownType, "Unknown type");
return utils::failure(utils::error{error_code::UnknownType, "Unknown type"});
}
// 1) Traverse relations first => dependencies will be inserted before this object
access::process(*this, *ptr);
try {
access::process(*this, *ptr);
} catch (const query_builder_exception &ex) {
return utils::failure(ex.error());
}
// 2) Build INSERT for this object
const auto &info = it->second.node().info();
@@ -291,27 +297,28 @@ private:
const auto cit = contexts_by_type_.find(it->second.node().info().type_index());
if (cit == contexts_by_type_.end()) {
throw query_builder_exception(error_code::UnknownType, "Unknown type");
return utils::failure(utils::error{error_code::UnknownType, "Unknown type"});
}
step.ctx = cit->second.insert;
step.bind_object = [ptr](sql::statement &stmt) { stmt.bind(*ptr); };
if (info.has_primary_key() && step.pk_generator == utils::generator_type::Identity) {
const auto pk_name = info.primary_key_attribute()->name();
const table_column pk_col(&it->second.table(), pk_name);
// step.query = fetchable_query{insert().into(it->second.table()).values(*ptr).returning(pk_col)};
step.apply_returning = [ptr, &step, pk_name = pk_name](const sql::record &rec) {
const auto& f = rec.at(pk_name);
utils::identifier id;
id.assign(f.value());
step.pk_accessor.set(*ptr, id);
};
} else if (info.has_primary_key() && step.pk_generator == utils::generator_type::Sequence || step.pk_generator == utils::generator_type::Table) {
} else if (info.has_primary_key() && (step.pk_generator == utils::generator_type::Sequence || step.pk_generator == utils::generator_type::Table)) {
step.apply_primary_key = [ptr, &step](const utils::identifier &id) {
step.pk_accessor.set(*ptr, id);
};
}
step.make_object_persistent = [ptr] { ptr.change_state(object::object_state::Persistent); };
steps.push_back(std::move(step));
return utils::ok<void>();
}
template<class Pointer>
+16 -25
View File
@@ -8,12 +8,10 @@
#include "matador/query/query.hpp"
#include "matador/query/query_contexts.hpp"
#include "matador/query/generator.hpp"
#include "matador/query/schema.hpp"
#include "matador/sql/connection.hpp"
#include "matador/sql/connection_pool.hpp"
#include "matador/sql/executor.hpp"
#include "matador/sql/record.hpp"
#include "matador/sql/resolver_service.hpp"
#include "matador/sql/statement.hpp"
#include "matador/sql/statement_cache.hpp"
@@ -42,7 +40,7 @@ struct session_context {
class session final /*: public sql::executor*/ {
public:
session(session_context &&ctx, const query::schema &scm);
session(session_context &&ctx, const basic_schema &scm);
/**
* Insert the given object into the session.
@@ -64,20 +62,14 @@ public:
template<typename Type>
utils::result<sql::query_result<Type>, utils::error> find(query::criteria_ptr clause = {});
// [[nodiscard]] utils::result<std::unique_ptr<sql::query_result_impl>, utils::error> fetch(const sql::query_context &ctx) const override;
// [[nodiscard]] utils::result<sql::execute_result, utils::error> execute(const sql::query_context &ctx) const override;
// [[nodiscard]] utils::result<sql::statement, utils::error> prepare(const sql::query_context &ctx) override;
// [[nodiscard]] std::string str(const sql::query_context &ctx) const override;
// [[nodiscard]] const sql::dialect &dialect() const override;
// [[nodiscard]] std::shared_ptr<sql::resolver_service> resolver() const override;
[[nodiscard]] const query::basic_schema &schema() const;
[[nodiscard]] const basic_schema &schema() const;
private:
sql::connection_pool pool_;
mutable sql::statement_cache cache_;
const sql::dialect &dialect_;
const query::basic_schema &schema_;
const basic_schema &schema_;
mutable std::unordered_map<std::string, std::vector<object::attribute> > prototypes_;
std::shared_ptr<sql::resolver_service> resolver_service_;
std::unordered_map<std::type_index, query::query_contexts> contexts_by_type_;
@@ -257,28 +249,26 @@ utils::result<object::object_ptr<Type>, utils::error> session::find(const Primar
if (it == schema_.end()) {
return utils::failure(make_error(error_code::UnknownType, "Failed to determine requested type."));
}
const auto &info = it->second.node().info();
if (!info.has_primary_key()) {
if (const auto &info = it->second.node().info(); !info.has_primary_key()) {
return utils::failure(make_error(error_code::FailedToFindPrimaryKey, "Type hasn't primary key."));
}
const auto cit = contexts_by_type_.find(it->second.node().info().type_index());
if (cit == contexts_by_type_.end()) {
return utils::failure(make_error(error_code::UnknownType, "Failed to determine requested type."));
select_query_builder eqb(schema_);
auto data = eqb.build<Type>(*it->second.table().primary_key_column() == pk);
if (!data.is_ok()) {
return utils::failure(make_error(error_code::FailedToBuildQuery,
"Failed to build query for type " + it->second.name() + "."));
}
auto stmt = cache_.acquire(cit->second.select_one);
auto ctx = data->compile(dialect_);
ctx.resolver = resolver_service_;
auto stmt = cache_.acquire(ctx);
if (!stmt.is_ok()) {
return utils::failure(stmt.err());
}
auto stmt_result = stmt->bind(0, const_cast<PrimaryKeyType &>(pk))
.template fetch_one<Type>();
if (!stmt_result) {
return utils::failure(make_error(error_code::FailedToFindObject,
"Failed to find object of type " + info.name() + " with primary key " +
std::to_string(pk) + "."));
}
return utils::ok(*stmt_result);
return stmt->template fetch_one<Type>();
}
template<typename Type>
@@ -296,6 +286,7 @@ utils::result<sql::query_result<Type>, utils::error> session::find(query::criter
}
auto ctx = data->compile(dialect_);
ctx.resolver = resolver_service_;
auto stmt = cache_.acquire(ctx);
if (!stmt.is_ok()) {
return utils::failure(stmt.err());
+17 -17
View File
@@ -7,23 +7,23 @@
namespace matador::sql {
enum class error_code : uint8_t {
OK = 0,
INVALID_QUERY,
UNKNOWN_TABLE,
UNKNOWN_COLUMN,
BIND_FAILED,
EXECUTE_FAILED,
FETCH_FAILED,
PREPARE_FAILED,
DESCRIBE_FAILED,
TABLE_EXISTS_FAILED,
RETRIEVE_DATA_FAILED,
SEQUENCE_EXISTS_FAILED,
RESET_FAILED,
OPEN_ERROR,
CLOSE_ERROR,
STATEMENT_LOCKED,
FAILURE
Ok = 0,
InvalidQuery,
UnknownTable,
UnknownColumn,
BindFailed,
ExecuteFailed,
FetchFailed,
PrepareFailed,
DescribeFailed,
TableExistsFailed,
RetrieveDataFailed,
SequenceExistsFailed,
ResetFailed,
OpenError,
CloseError,
StatementLocked,
Failure
};
class sql_category_impl final : public std::error_category
@@ -21,6 +21,9 @@ public:
static void on_base(const BaseType&) {}
template < class Type >
void on_primary_key(const char * /*id*/, Type &val, const utils::primary_key_attribute& attr) {
if (attr.generator() == utils::generator_type::Identity) {
return;
}
utils::data_type_traits<Type>::bind_value(*binder_, index_++, val, attr.size());
}
void on_revision(const char *id, uint64_t &/*rev*/);
+1 -1
View File
@@ -38,7 +38,7 @@ struct query_context {
std::string table_name{};
std::vector<object::attribute> prototype{};
std::vector<std::string> bind_vars{};
std::vector<utils::database_type> bind_types{};
// std::vector<utils::database_type> bind_types{};
// Data for resolving query result
std::shared_ptr<resolver_service> resolver{};
std::type_index result_type = typeid(void);
+1 -1
View File
@@ -196,7 +196,7 @@ utils::result<object::object_ptr<Type>, utils::error> statement::fetch_one() {
});
auto first = records.begin();
if (first == records.end()) {
return utils::failure(utils::error{error_code::FETCH_FAILED,"Failed to find entity."});
return utils::failure(utils::error{error_code::FetchFailed,"Failed to find entity."});
}
return utils::ok(first.optr());