Files
secondo/Algebras/DBService2/Relation.hpp

342 lines
10 KiB
C++
Raw Permalink Normal View History

2026-01-23 17:03:45 +08:00
#ifndef DBS_RELATION_H
#define DBS_RELATION_H
#include "Algebras/DBService2/Record.hpp"
#include "Algebras/DBService2/Node.hpp"
#include "Algebras/DBService2/Query.hpp"
#include "Algebras/DBService2/Replica.hpp"
#include "Algebras/DBService2/SecondoRelationAdapter.hpp"
#include "Algebras/DBService2/Derivative.hpp"
#include <string>
#include <vector>
namespace DBService {
// Forward declaration
class Replica;
class SecondoRelationAdapter;
class Derivative;
/*
Represents Relations replicated using the DBService.
Saves original Nodes before saving the Relation.
Does not save target Nodes. They are assumed to already exist as the
result of addNode operator invocations when setting up the DB Service
cluster.
*/
//class Relation : public Record<DBService::Relation, SecondoRelationAdapter>, public std::enable_shared_from_this<DBService::Relation> {
class Relation : public Record<DBService::Relation, SecondoRelationAdapter> {
private:
std::string relationDatabase;
std::string name;
std::shared_ptr<DBService::Node> originalNode;
// https://stackoverflow.com/questions/11711034/stdshared-ptr-of-this
std::vector<std::shared_ptr<DBService::Replica> > replicas;
std::vector<std::shared_ptr<DBService::Derivative> > derivatives;
void saveReplicas();
void saveDerivatives();
protected:
/*
The use of enable_shared_from_this requires that prior to making
a shared_ptr from this, another shared_ptr for this object must exist.
The easiest way to ensure this is to declare the constructor proteced
and force the usage of factory methods called ~build~ which in turn
creates a shared_ptr.
*/
Relation();
/*
The relationDatabase is the database in which the relation with "name" is
stored. It is not the database of the Relation record.
*/
Relation(std::string relationDatabase, std::string relationName);
Relation(std::string relationDatabase, std::string relationName,
std::shared_ptr<DBService::Node> originalNode);
Relation(std::string relationDatabase, std::string relationName,
std::string originalNodeHost, int originalNodePort,
std::string originalNodeDisk);
public:
static std::shared_ptr<DBService::Relation> build();
static std::shared_ptr<DBService::Relation> build(
std::string relationDatabase, std::string relationName);
static std::shared_ptr<DBService::Relation> build(
std::string relationDatabase, std::string relationName,
std::shared_ptr<DBService::Node> originalNode);
static std::shared_ptr<DBService::Relation> build(
std::string relationDatabase, std::string relationName,
std::string originalNodeHost, int originalNodePort,
std::string originalNodeDisk);
/*
In contrast to getDatabase() inherited from the Record superclass,
getRelationDatabase() returns the Relation attribute relationDatabase
which describes the database of the originalSystem holding the relation
represented by the given Relation object.
*/
std::string getRelationDatabase() const;
/*
Sets the Relation's relationDatabase property.
Converts the name to uppercase before assignment as DB comparisons
are done in uppercase.
*/
void setRelationDatabase(std::string newRelationDatabase);
/*
Returns the Relation's name.
*/
std::string getName() const;
std::shared_ptr<DBService::Node> getOriginalNode() const;
void setOriginalNode(std::shared_ptr<DBService::Node> newOriginalNode);
// It is not allowed to change the name of a relation.
void setName(std::string newName);
/*
Very short string description of the given Relation.
Use ~str()~ over ~operator<<~ when printing a Relation as part of
other Records that will also be part of Relation's ~operator<<~.
The ~operator<<~ is meant to recursively print all dependent objects
and these dependent objects will indicate their references to a relation
by using the short ~str()~. This also presents indefinite loops.
*/
std::string str(int indentationLevel = 0) const;
// Replicas START
std::vector<std::shared_ptr<Replica> > getReplicas() const;
/*
Returns the number of Replica objects held in-memory.
Note that the number of persisted Replicas may be different.
*/
int getReplicaCount() const;
/*
Adds the given replica and sets the database as well
as the relation of the Replica to the parent Relation.
The operation is performed in-memory, only.
The Relation is considered "dirty" (unsaved) after
the execution of ~addReplica~.
*/
void addReplica(std::shared_ptr<Replica> newReplica);
/*
After a target Node for a Replica of the given Relation has been
determined, this function can be used to add the Replica and associate
it with the Relation.
The operation is performed in-memory, only.
The Relation is considered "dirty" (unsaved) after
the execution of ~addReplica~.
The targetNode must be non-new so that it already has an id.
*/
void addReplica(std::shared_ptr<DBService::Node> targetNode);
/*
Checks whether a given Replica already exists in-memory.
*/
bool doesReplicaExist(std::shared_ptr<Replica> newReplica);
/*
Finds a Replica associated with the given Relation by
the host and port of the Replic's target Node.
Returns ~nullptr~ in case none if found.
*/
std::shared_ptr<Replica> findReplica(std::string targetHost,
int targetPort, std::string replicaType = "relation");
/*
Finds Replicas belonging to Derivatives.
Returns ~nullptr~ if none are found.
*/
std::shared_ptr<Replica> findReplicaByDerivativeId(std::string targetHost,
int targetPort, int derivativeId);
/*
Finds the Replica associated with the target Node specified by the
given ~targetHost~ and ~targetPort~, updates the Replica status to
~replicaStatus~ and saves the replica.
*/
void updateReplicaStatus(std::string targetHost, int targetPort,
std::string replicaStatus);
/*
Removes unsaved (dirty) Replicas from the list of replicas.
Does not change the Relations's dirty status.
TODO Rename method to "removeDirtyReplicas". Describes the semantics
more accurately.
*/
void resetReplicas();
std::shared_ptr<Replica> getRandomReplica() const;
/*
Load all replicas belonging to the given Relation.
*/
void loadReplicas();
/*
Destroy alls replicas by invoking ~destroy~.
*/
void deleteReplicas();
// Replicas END
// Derivates START
/*
Builds a Derivative from the given ~derivativeName~ and ~function~ and
associates the Derivative with the given Relation.
This will also create a derivate Replica for each relation Replica of the
Relation.
The relation is "dirty" afterwards.
*/
std::shared_ptr<DBService::Derivative>
addDerivative (std::string derivativeName, std::string function);
/*
Returns the number of in-memory Derivatives held by the Relation.
*/
int getDerivativeCount() const;
std::vector<std::shared_ptr<DBService::Derivative> > getDerivatives();
/*
Loads associated Derivatives.
*/
void loadDerivatives();
/*
Finds the Replica associated with the target Node specified by the
given ~targetHost~ and ~targetPort~ of the given ~Derivative~,
updates the Replica status to
~replicaStatus~ and saves the replica.
*/
void updateDerivativeReplicaStatus(std::string derivativeName,
std::string targetHost, int targetPort, std::string replicaStatus);
/*
Find a Derivative by its id.
Returns ~nullptr~ if none is found.
*/
std::shared_ptr<Derivative> findDerivative(int derivativeId);
/*
Find a Derivative by its name.
Returns ~nullptr~ if none is found.
*/
std::shared_ptr<Derivative> findDerivative(std::string derivativeName);
/*
Returns ~true~ if a Derivative with the provided ~derivativeName~ exists.
return ~false~ otherwise.
*/
bool doesDerivativeExist(std::string derivativeName);
/*
Destroy all derivatives by invoking ~destroy~.
*/
void deleteDerivatives();
/*
Destroy derivative and remove it from the relation.
*/
void deleteDerivative(std::string derivativeName);
// Derivatives END
/*
* Record START
*/
/*
Returns the name of the Relation's record relation (as in database table).
*/
static std::string getRelationName();
static std::string createRelationStatement();
std::string createStatement() const;
/*
It is not possible to update an existing Relation's attributes such as
the ~relationName~ or ~relationDatabase~.
Therefore the updateStatement() returns a non-mutating statement that
can be executed by the Record's save implementation.
The purpose of this is that still ~before_save~ and ~after_save~ methods
will be triggered.
~Replicas~, for example, may very well be updated and their updates can
be triggered by updating their ~Relation~.
*/
std::string updateStatement() const;
/*
Trigger saving the originalNode before saving the relation.
*/
void beforeSave();
/*
Trigger saving the Replicas after saving the relation.
*/
void afterSave();
void afterDestroy();
bool empty() const;
bool operator==(const DBService::Relation &other) const;
bool operator!=(const DBService::Relation &other) const;
void loadOriginalNode(int originalNodeId);
static Query query(std::string database);
static std::string findAllStatement(std::string database);
static std::vector<std::shared_ptr<Relation> > findAll(
std::string database);
/*
Returns the Relation if found or ~nullptr~ otherwise.
*/
static std::shared_ptr<Relation> findOne(std::string database, Query query);
/*
* Record END
*/
static Query queryByDatabaseAndName(std::string database,
std::string relationDatabase, std::string relationName);
};
// Record
// Print relation
std::ostream &operator<<(std::ostream &os,
DBService::Relation &relation);
}
#endif