refactor and complete parts of the knowledge base

This commit is contained in:
Chris Cromer 2023-02-18 21:06:42 -03:00
parent b220b1c215
commit 91cce4c170
Signed by: cromer
GPG Key ID: FA91071797BEEEC2
17 changed files with 851 additions and 29 deletions

View File

@ -1,11 +1,5 @@
#include "knowledge_base.h" #include "knowledge_base.h"
#include "models/action.h"
#include "models/entity.h"
#include "models/error.h" #include "models/error.h"
#include "models/fact.h"
#include "models/rule.h"
#include "models/suggest_action.h"
#include "models/verb.h"
#include <cstring> #include <cstring>
#include <filesystem> #include <filesystem>
@ -119,6 +113,25 @@ void obelisk::KnowledgeBase::addVerbs(std::vector<obelisk::Verb>& verbs)
} }
} }
void obelisk::KnowledgeBase::addActions(std::vector<obelisk::Action>& actions)
{
for (auto& action : actions)
{
try
{
action.insert(dbConnection_);
}
catch (obelisk::DatabaseConstraintException& exception)
{
// ignore unique constraint error
if (std::strcmp(exception.what(), "UNIQUE constraint failed: action.name") != 0)
{
throw;
}
}
}
}
void obelisk::KnowledgeBase::addFacts(std::vector<obelisk::Fact>& facts) void obelisk::KnowledgeBase::addFacts(std::vector<obelisk::Fact>& facts)
{ {
for (auto& fact : facts) for (auto& fact : facts)
@ -150,9 +163,14 @@ void obelisk::KnowledgeBase::getVerb(obelisk::Verb& verb)
verb.selectByName(dbConnection_); verb.selectByName(dbConnection_);
} }
void obelisk::KnowledgeBase::getAction(obelisk::Action& action)
{
action.selectByName(dbConnection_);
}
void obelisk::KnowledgeBase::getFact(obelisk::Fact& fact) void obelisk::KnowledgeBase::getFact(obelisk::Fact& fact)
{ {
fact.selectByName(dbConnection_); fact.selectById(dbConnection_);
} }
void obelisk::KnowledgeBase::getFloat(float& result1, float& result2, double var) void obelisk::KnowledgeBase::getFloat(float& result1, float& result2, double var)

View File

@ -1,8 +1,11 @@
#ifndef OBELISK_KNOWLEDGE_BASE_H #ifndef OBELISK_KNOWLEDGE_BASE_H
#define OBELISK_KNOWLEDGE_BASE_H #define OBELISK_KNOWLEDGE_BASE_H
#include "models/action.h"
#include "models/entity.h" #include "models/entity.h"
#include "models/fact.h" #include "models/fact.h"
#include "models/rule.h"
#include "models/suggest_action.h"
#include "models/verb.h" #include "models/verb.h"
#include <sqlite3.h> #include <sqlite3.h>
@ -23,7 +26,7 @@ namespace obelisk
{ {
private: private:
/** /**
* @brief The filename of the opened knowledge base. * @brief The filename of the opened KnowledgeBase.
* *
*/ */
const char* filename_; const char* filename_;
@ -61,7 +64,7 @@ namespace obelisk
* *
* @param[in] filename The name of the file to save the knowledge * @param[in] filename The name of the file to save the knowledge
* base as. * base as.
* @param[in] flags The flags to open the knowledge base with. * @param[in] flags The flags to open the KnowledgeBase with.
*/ */
KnowledgeBase(const char* filename, int flags); KnowledgeBase(const char* filename, int flags);
@ -79,12 +82,12 @@ namespace obelisk
/** /**
* @brief Destroy the KnowledgeBase object. * @brief Destroy the KnowledgeBase object.
* *
* This will close the opened knowledge base before destroying it. * This will close the opened KnowledgeBase before destroying it.
*/ */
~KnowledgeBase(); ~KnowledgeBase();
/** /**
* @brief Add entities to the knowledge base. * @brief Add entities to the KnowledgeBase.
* *
* @param[in,out] entities The entities to add. If the insert is * @param[in,out] entities The entities to add. If the insert is
* successful it will have a row ID, if not the ID will be 0. * successful it will have a row ID, if not the ID will be 0.
@ -92,13 +95,21 @@ namespace obelisk
void addEntities(std::vector<obelisk::Entity>& entities); void addEntities(std::vector<obelisk::Entity>& entities);
/** /**
* @brief Add verbs to the knowledge base. * @brief Add verbs to the KnowledgeBase.
* *
* @param[in,out] verbs The verbs to add. If the insert is * @param[in,out] verbs The verbs to add. If the insert is
* successful it will have a row ID, if not the ID will be 0. * successful it will have a row ID, if not the ID will be 0.
*/ */
void addVerbs(std::vector<obelisk::Verb>& verbs); void addVerbs(std::vector<obelisk::Verb>& verbs);
/**
* @brief Add actions to the KnowledgeBase.
*
* @param[in,out] actions The actions to add. If the insert is
* successful it will have a row ID, if nto the ID will be 0.
*/
void addActions(std::vector<obelisk::Action>& actions);
/** /**
* @brief Add facts to the database. * @brief Add facts to the database.
* *
@ -123,6 +134,14 @@ namespace obelisk
*/ */
void getVerb(obelisk::Verb& verb); void getVerb(obelisk::Verb& verb);
/**
* @brief Get an action based on the ID it contains.
*
* @param[in] action The Action object should contain just the ID
* and the rest will be filled in.
*/
void getAction(obelisk::Action& action);
/** /**
* @brief Get a fact object based on the ID it contains. * @brief Get a fact object based on the ID it contains.
* *

View File

@ -9,7 +9,8 @@ configure_file(input : 'version.h.in',
subdir('models') subdir('models')
obelisk_lib_sources = files( obelisk_lib_sources = files(
'obelisk.cpp' 'obelisk.cpp',
'knowledge_base.cpp'
) )
obelisk_lib_sources += obelisk_model_sources obelisk_lib_sources += obelisk_model_sources

View File

@ -1,4 +1,5 @@
#include "models/action.h" #include "models/action.h"
#include "models/error.h"
const char* obelisk::Action::createTable() const char* obelisk::Action::createTable()
{ {
@ -11,6 +12,131 @@ const char* obelisk::Action::createTable()
)"; )";
} }
void obelisk::Action::selectByName(sqlite3* dbConnection)
{
if (dbConnection == nullptr)
{
throw obelisk::DatabaseException("database isn't open");
}
sqlite3_stmt* ppStmt = nullptr;
auto result = sqlite3_prepare_v2(dbConnection, "SELECT id, name FROM action WHERE name=?", -1, &ppStmt, nullptr);
if (result != SQLITE_OK)
{
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
}
result = sqlite3_bind_text(ppStmt, 1, getName().c_str(), -1, SQLITE_STATIC);
switch (result)
{
case SQLITE_OK :
break;
case SQLITE_TOOBIG :
throw obelisk::DatabaseSizeException();
break;
case SQLITE_RANGE :
throw obelisk::DatabaseRangeException();
break;
case SQLITE_NOMEM :
throw obelisk::DatabaseMemoryException();
break;
default :
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
break;
}
result = sqlite3_step(ppStmt);
switch (result)
{
case SQLITE_DONE :
// no rows in the database
break;
case SQLITE_ROW :
setId(sqlite3_column_int(ppStmt, 0));
setName((char*) sqlite3_column_text(ppStmt, 1));
break;
case SQLITE_BUSY :
throw obelisk::DatabaseBusyException();
break;
case SQLITE_MISUSE :
throw obelisk::DatabaseMisuseException();
break;
default :
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
break;
}
result = sqlite3_finalize(ppStmt);
if (result != SQLITE_OK)
{
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
}
}
void obelisk::Action::insert(sqlite3* dbConnection)
{
if (dbConnection == nullptr)
{
throw obelisk::DatabaseException("database isn't open");
}
sqlite3_stmt* ppStmt = nullptr;
auto result = sqlite3_prepare_v2(dbConnection, "INSERT INTO action (name) VALUES (?)", -1, &ppStmt, nullptr);
if (result != SQLITE_OK)
{
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
}
result = sqlite3_bind_text(ppStmt, 1, getName().c_str(), -1, SQLITE_TRANSIENT);
switch (result)
{
case SQLITE_OK :
break;
case SQLITE_TOOBIG :
throw obelisk::DatabaseSizeException();
break;
case SQLITE_RANGE :
throw obelisk::DatabaseRangeException();
break;
case SQLITE_NOMEM :
throw obelisk::DatabaseMemoryException();
break;
default :
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
break;
}
result = sqlite3_step(ppStmt);
switch (result)
{
case SQLITE_DONE :
setId((int) sqlite3_last_insert_rowid(dbConnection));
sqlite3_set_last_insert_rowid(dbConnection, 0);
break;
case SQLITE_CONSTRAINT :
throw obelisk::DatabaseConstraintException(sqlite3_errmsg(dbConnection));
case SQLITE_BUSY :
throw obelisk::DatabaseBusyException();
break;
case SQLITE_MISUSE :
throw obelisk::DatabaseMisuseException();
break;
default :
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
break;
}
result = sqlite3_finalize(ppStmt);
if (result != SQLITE_OK)
{
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
}
}
int& obelisk::Action::getId() int& obelisk::Action::getId()
{ {
return id_; return id_;

View File

@ -1,6 +1,8 @@
#ifndef OBELISK_MODELS_ACTION_H #ifndef OBELISK_MODELS_ACTION_H
#define OBELISK_MODELS_ACTION_H #define OBELISK_MODELS_ACTION_H
#include <sqlite3.h>
#include <string> #include <string>
namespace obelisk namespace obelisk
@ -14,7 +16,7 @@ namespace obelisk
{ {
private: private:
/** /**
* @brief The ID of the Action in the knowledge base. * @brief The ID of the Action in the KnowledgeBase.
* *
*/ */
int id_; int id_;
@ -71,7 +73,7 @@ namespace obelisk
} }
/** /**
* @brief Create the Action table in the knowledge base. * @brief Create the Action table in the KnowledgeBase.
* *
* @return const char* Returns the query used to create the table. * @return const char* Returns the query used to create the table.
*/ */
@ -104,6 +106,22 @@ namespace obelisk
* @param[in] name The name of the Action. * @param[in] name The name of the Action.
*/ */
void setName(std::string name); void setName(std::string name);
/**
* @brief Select an Action from the datbase based on the object
* name.
*
* @param[in] dbConnection The database connection to use.
*/
void selectByName(sqlite3* dbConnection);
/**
* @brief Insert an Action into the KnowledgeBase based on the
* object's fields.
*
* @param[in] dbConnection The database connection to use.
*/
void insert(sqlite3* dbConnection);
}; };
} // namespace obelisk } // namespace obelisk

View File

@ -16,10 +16,11 @@ namespace obelisk
{ {
private: private:
/** /**
* @brief The ID of the Entity. * @brief The ID of the Entity in the KnowledgeBase.
* *
*/ */
int id_; int id_;
/** /**
* @brief The name of the Entity. * @brief The name of the Entity.
* *
@ -72,7 +73,7 @@ namespace obelisk
} }
/** /**
* @brief Create the table in the knowledge base. * @brief Create the table in the KnowledgeBase.
* *
* @return const char* Returns the query used to create the table. * @return const char* Returns the query used to create the table.
*/ */
@ -107,7 +108,7 @@ namespace obelisk
void setName(std::string name); void setName(std::string name);
/** /**
* @brief Select an Entity from the database based on the object's * @brief Select an Entity from the KnowledgeBase based on the object's
* name. * name.
* *
* @param[in] dbConnection The database connection to use. * @param[in] dbConnection The database connection to use.
@ -115,7 +116,7 @@ namespace obelisk
void selectByName(sqlite3* dbConnection); void selectByName(sqlite3* dbConnection);
/** /**
* @brief Insert an Entity into the database based on the object's * @brief Insert an Entity into the KnowledgeBase based on the object's
* fields. * fields.
* *
* @param[in] dbConnection The database connection to use. * @param[in] dbConnection The database connection to use.

View File

@ -6,77 +6,152 @@
namespace obelisk namespace obelisk
{ {
/**
* @brief Exception thrown by database models.
*
*/
class DatabaseException : public std::exception class DatabaseException : public std::exception
{ {
protected: protected:
/**
* @brief The error message describing the exception.
*
*/
std::string errorMessage_; std::string errorMessage_;
public: public:
/**
* @brief Construct a new DatabaseException object.
*
*/
DatabaseException() : DatabaseException() :
errorMessage_("an unknown error ocurred") errorMessage_("an unknown error ocurred")
{ {
} }
/**
* @brief Construct a new DatabaseException object.
*
* @param[in] errorCode The error code that came from sqlite.
*/
DatabaseException(const int errorCode) : DatabaseException(const int errorCode) :
errorMessage_("database error " + std::to_string(errorCode) + " ocurred") errorMessage_("database error " + std::to_string(errorCode) + " ocurred")
{ {
} }
/**
* @brief Construct a new DatabaseException object.
*
* @param[in] errorMessage The error message to describe the
* exception.
*/
DatabaseException(const std::string& errorMessage) : DatabaseException(const std::string& errorMessage) :
errorMessage_(errorMessage) errorMessage_(errorMessage)
{ {
} }
/**
* @brief Retreive the exception message as a C type string.
*
* @return const char* The error message.
*/
virtual const char* what() const noexcept virtual const char* what() const noexcept
{ {
return errorMessage_.c_str(); return errorMessage_.c_str();
} }
/**
* @brief Set the error message.
*
* @param[in] errorMessage The error message.
*/
virtual void setErrorMessage(const std::string errorMessage) virtual void setErrorMessage(const std::string errorMessage)
{ {
errorMessage_ = errorMessage; errorMessage_ = errorMessage;
} }
}; };
/**
* @brief Exception thrown if the string or blob size exceeds sqlite's
* limits.
*
*/
class DatabaseSizeException : public obelisk::DatabaseException class DatabaseSizeException : public obelisk::DatabaseException
{ {
public: public:
/**
* @brief Construct a new DatabaseSizeException object.
*
*/
DatabaseSizeException() DatabaseSizeException()
{ {
setErrorMessage("size of string or blob exceeds limits"); setErrorMessage("size of string or blob exceeds limits");
} }
}; };
/**
* @brief Exception thrown if the index used it out of range.
*
*/
class DatabaseRangeException : public obelisk::DatabaseException class DatabaseRangeException : public obelisk::DatabaseException
{ {
public: public:
/**
* @brief Construct a new DatabaseRangeException object.
*
*/
DatabaseRangeException() DatabaseRangeException()
{ {
setErrorMessage("parameter index is out of range"); setErrorMessage("parameter index is out of range");
} }
}; };
/**
* @brief Exception thrown if there is not enough memory to perform the
* operation.
*
*/
class DatabaseMemoryException : public obelisk::DatabaseException class DatabaseMemoryException : public obelisk::DatabaseException
{ {
public: public:
/**
* @brief Construct a new DatabaseMemoryException object.
*
*/
DatabaseMemoryException() DatabaseMemoryException()
{ {
setErrorMessage("not enough memory for operation"); setErrorMessage("not enough memory for operation");
} }
}; };
/**
* @brief Exception thrown if the database was busy.
*
*/
class DatabaseBusyException : public obelisk::DatabaseException class DatabaseBusyException : public obelisk::DatabaseException
{ {
public: public:
/**
* @brief Construct a new DatabaseBusyException object.
*
*/
DatabaseBusyException() DatabaseBusyException()
{ {
setErrorMessage("database was busy and operation was not performed"); setErrorMessage("database was busy and operation was not performed");
} }
}; };
/**
* @brief Exception thrown if there is a misuse of the databse.
*
*/
class DatabaseMisuseException : public obelisk::DatabaseException class DatabaseMisuseException : public obelisk::DatabaseException
{ {
public: public:
/**
* @brief Construct a new DatabaseMisuseException object.
*
*/
DatabaseMisuseException() DatabaseMisuseException()
{ {
@ -84,14 +159,28 @@ namespace obelisk
} }
}; };
/**
* @brief Exception thrown if a constraint was violated.
*
*/
class DatabaseConstraintException : public obelisk::DatabaseException class DatabaseConstraintException : public obelisk::DatabaseException
{ {
public: public:
/**
* @brief Construct a new DatabaseConstraintException object.
*
*/
DatabaseConstraintException() DatabaseConstraintException()
{ {
setErrorMessage("a constraint exception occurred"); setErrorMessage("a constraint exception occurred");
} }
/**
* @brief Construct a new DatabaseConstraintException object.
*
* @param[in] errorMessage The error message to send when the
* constraint is violated.
*/
DatabaseConstraintException(const std::string& errorMessage) DatabaseConstraintException(const std::string& errorMessage)
{ {
setErrorMessage(errorMessage); setErrorMessage(errorMessage);

View File

@ -19,7 +19,7 @@ const char* obelisk::Fact::createTable()
)"; )";
} }
void obelisk::Fact::selectByName(sqlite3* dbConnection) void obelisk::Fact::selectById(sqlite3* dbConnection)
{ {
if (dbConnection == nullptr) if (dbConnection == nullptr)
{ {

View File

@ -9,16 +9,50 @@
namespace obelisk namespace obelisk
{ {
/**
* @brief The Fact model represents truth in the releationship between two
* entities separated by a verb.
*
*/
class Fact class Fact
{ {
private: private:
/**
* @brief The ID of the Fact in the KnowledgeBase.
*
*/
int id_; int id_;
/**
* @brief The Entity from the left side of the expression.
*
*/
obelisk::Entity leftEntity_; obelisk::Entity leftEntity_;
/**
* @brief The Entity from the right side of the expression.
*
*/
obelisk::Entity rightEntity_; obelisk::Entity rightEntity_;
/**
* @brief The Verb that represents the relationship in the
* expression.
*
*/
obelisk::Verb verb_; obelisk::Verb verb_;
/**
* @brief Whether or not the fact is considered true or not.
*
*/
bool isTrue_; bool isTrue_;
public: public:
/**
* @brief Construct a new Fact object.
*
*/
Fact() : Fact() :
id_(0), id_(0),
leftEntity_(), leftEntity_(),
@ -28,6 +62,11 @@ namespace obelisk
{ {
} }
/**
* @brief Construct a new Fact object.
*
* @param[in] id The ID of the Fact in the KnowledgeBase.
*/
Fact(int id) : Fact(int id) :
id_(id), id_(id),
leftEntity_(), leftEntity_(),
@ -37,6 +76,16 @@ namespace obelisk
{ {
} }
/**
* @brief Construct a new Fact object.
*
* @param[in] leftEntity The Entity on the left side of the
* expression.
* @param[in] rightEntity The Entity on the right side of the
* expression.
* @param[in] verb The Verb separating the entities.
* @param[in] isTrue Whether or not the fact is true.
*/
Fact(obelisk::Entity leftEntity, obelisk::Entity rightEntity, obelisk::Verb verb, bool isTrue = false) : Fact(obelisk::Entity leftEntity, obelisk::Entity rightEntity, obelisk::Verb verb, bool isTrue = false) :
id_(0), id_(0),
leftEntity_(leftEntity), leftEntity_(leftEntity),
@ -46,6 +95,17 @@ namespace obelisk
{ {
} }
/**
* @brief Construct a new Fact object.
*
* @param[in] id The ID of the Fact in the KnowledgeBase.
* @param[in] leftEntity The Entity on the left side of the
* expression.
* @param[in] rightEntity The Entity on the right side of the
* expression.
* @param[in] verb The Verb separating the entities.
* @param[in] isTrue Whether or not the fact is true.
*/
Fact(int id, Fact(int id,
obelisk::Entity leftEntity, obelisk::Entity leftEntity,
obelisk::Entity rightEntity, obelisk::Entity rightEntity,
@ -59,24 +119,97 @@ namespace obelisk
{ {
} }
/**
* @brief Create the Fact table in the KnowledgeBase.
*
* @return const char* Returns the query used to create the table.
*/
static const char* createTable(); static const char* createTable();
/**
* @brief Get the ID of the Fact
*
* @return int& Returns the ID.
*/
int& getId(); int& getId();
/**
* @brief Set the ID of the Fact.
*
* @param[in] id Set the ID of the Fact.
*/
void setId(int id); void setId(int id);
/**
* @brief Get the left Entity object.
*
* @return Entity& The left Entity.
*/
Entity& getLeftEntity(); Entity& getLeftEntity();
/**
* @brief Set the left Entity object.
*
* @param[in] leftEntity The left Entity to set.
*/
void setLeftEntity(obelisk::Entity leftEntity); void setLeftEntity(obelisk::Entity leftEntity);
/**
* @brief Get the right Entity object.
*
* @return Entity& The right Entity.
*/
Entity& getRightEntity(); Entity& getRightEntity();
void setRightEntity(obelisk::Entity leftEntity);
/**
* @brief Set the right Entity object.
*
* @param[in] rightEntity The right Entity to set.
*/
void setRightEntity(obelisk::Entity rightEntity);
/**
* @brief Get the Verb object.
*
* @return Verb& The Verb.
*/
Verb& getVerb(); Verb& getVerb();
/**
* @brief Set the Verb object.
*
* @param[in] verb The Verb.
*/
void setVerb(obelisk::Verb verb); void setVerb(obelisk::Verb verb);
/**
* @brief Gets the isTrue value.
*
* @return true If the Fact is considered true.
* @return false If the Fact is considered false.
*/
bool& getIsTrue(); bool& getIsTrue();
/**
* @brief Set the Fact as true or false.
*
* @param[in] isTrue Whether or not the Fact is true.
*/
void setIsTrue(bool isTrue); void setIsTrue(bool isTrue);
void selectByName(sqlite3* dbConnection); /**
* @brief Select the Fact from the KnowledgeBase by IDs of the
* sub-objects.
*
* @param[in] dbConnection The database connection to use.
*/
void selectById(sqlite3* dbConnection);
/**
* @brief Insert the Fact into the KnowledgeBase.
*
* @param[in] dbConnection The database connection to use.
*/
void insert(sqlite3* dbConnection); void insert(sqlite3* dbConnection);
}; };
} // namespace obelisk } // namespace obelisk

View File

@ -7,14 +7,36 @@
namespace obelisk namespace obelisk
{ {
/**
* @brief The Rule model represents a truth relation between 2 Facts.
*
*/
class Rule class Rule
{ {
private: private:
/**
* @brief The ID of the Rule in the KnowledgeBase.
*
*/
int id_; int id_;
/**
* @brief The Fact that depends on the Fact reason being true.
*
*/
obelisk::Fact fact_; obelisk::Fact fact_;
/**
* @brief The Fact that makes the other Fact true or false.
*
*/
obelisk::Fact reason_; obelisk::Fact reason_;
public: public:
/**
* @brief Construct a new Rule object.
*
*/
Rule() : Rule() :
id_(0), id_(0),
fact_(), fact_(),
@ -22,6 +44,11 @@ namespace obelisk
{ {
} }
/**
* @brief Construct a new Rule object.
*
* @param[in] id The ID of the Rule in the KnowledgeBase.
*/
Rule(int id) : Rule(int id) :
id_(id), id_(id),
fact_(), fact_(),
@ -29,6 +56,12 @@ namespace obelisk
{ {
} }
/**
* @brief Construct a new Rule object.
*
* @param[in] fact The Fact.
* @param[in] reason The reason Fact.
*/
Rule(obelisk::Fact fact, obelisk::Fact reason) : Rule(obelisk::Fact fact, obelisk::Fact reason) :
id_(0), id_(0),
fact_(fact), fact_(fact),
@ -36,6 +69,13 @@ namespace obelisk
{ {
} }
/**
* @brief Construct a new Rule object.
*
* @param[in] id The ID of the Rule.
* @param[in] fact The Fact.
* @param[in] reason The reason Fact.
*/
Rule(int id, obelisk::Fact fact, obelisk::Fact reason) : Rule(int id, obelisk::Fact fact, obelisk::Fact reason) :
id_(id), id_(id),
fact_(fact), fact_(fact),
@ -43,15 +83,53 @@ namespace obelisk
{ {
} }
/**
* @brief Create the Rule table in the KnowledgeBase.
*
* @return const char* Returns the query used to create the table.
*/
static const char* createTable(); static const char* createTable();
/**
* @brief Get the ID of the Rule.
*
* @return int& The ID.
*/
int& getId(); int& getId();
/**
* @brief Set the ID of the Rule.
*
* @param[in] id The ID.
*/
void setId(int id); void setId(int id);
/**
* @brief Get the Fact object.
*
* @return obelisk::Fact& The Fact.
*/
obelisk::Fact& getFact(); obelisk::Fact& getFact();
/**
* @brief Set the Fact object.
*
* @param[in] fact The Fact.
*/
void setFact(obelisk::Fact fact); void setFact(obelisk::Fact fact);
/**
* @brief Get the reason Fact object.
*
* @return obelisk::Fact& The reason Fact.
*/
obelisk::Fact& getReason(); obelisk::Fact& getReason();
/**
* @brief Set the reason Fact object.
*
* @param[in] reason The reason Fact.
*/
void setReason(obelisk::Fact reason); void setReason(obelisk::Fact reason);
}; };
} // namespace obelisk } // namespace obelisk

View File

@ -1,3 +1,4 @@
#include "models/error.h"
#include "models/suggest_action.h" #include "models/suggest_action.h"
const char* obelisk::SuggestAction::createTable() const char* obelisk::SuggestAction::createTable()
@ -17,6 +18,215 @@ const char* obelisk::SuggestAction::createTable()
)"; )";
} }
void obelisk::SuggestAction::selectById(sqlite3* dbConnection)
{
if (dbConnection == nullptr)
{
throw obelisk::DatabaseException("database isn't open");
}
sqlite3_stmt* ppStmt = nullptr;
auto result = sqlite3_prepare_v2(dbConnection,
"SELECT id, fact, true_action, false_action FROM suggest_action WHERE (fact=? AND true_action=? AND false_action=?)",
-1,
&ppStmt,
nullptr);
if (result != SQLITE_OK)
{
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
}
result = sqlite3_bind_int(ppStmt, 1, getFact().getId());
switch (result)
{
case SQLITE_OK :
break;
case SQLITE_TOOBIG :
throw obelisk::DatabaseSizeException();
break;
case SQLITE_RANGE :
throw obelisk::DatabaseRangeException();
break;
case SQLITE_NOMEM :
throw obelisk::DatabaseMemoryException();
break;
default :
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
break;
}
result = sqlite3_bind_int(ppStmt, 2, getTrueAction().getId());
switch (result)
{
case SQLITE_OK :
break;
case SQLITE_TOOBIG :
throw obelisk::DatabaseSizeException();
break;
case SQLITE_RANGE :
throw obelisk::DatabaseRangeException();
break;
case SQLITE_NOMEM :
throw obelisk::DatabaseMemoryException();
break;
default :
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
break;
}
result = sqlite3_bind_int(ppStmt, 3, getFalseAction().getId());
switch (result)
{
case SQLITE_OK :
break;
case SQLITE_TOOBIG :
throw obelisk::DatabaseSizeException();
break;
case SQLITE_RANGE :
throw obelisk::DatabaseRangeException();
break;
case SQLITE_NOMEM :
throw obelisk::DatabaseMemoryException();
break;
default :
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
break;
}
result = sqlite3_step(ppStmt);
switch (result)
{
case SQLITE_DONE :
// no rows in the database
break;
case SQLITE_ROW :
setId(sqlite3_column_int(ppStmt, 0));
getFact().setId(sqlite3_column_int(ppStmt, 1));
getTrueAction().setId(sqlite3_column_int(ppStmt, 2));
getFalseAction().setId(sqlite3_column_int(ppStmt, 3));
break;
case SQLITE_BUSY :
throw obelisk::DatabaseBusyException();
break;
case SQLITE_MISUSE :
throw obelisk::DatabaseMisuseException();
break;
default :
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
break;
}
result = sqlite3_finalize(ppStmt);
if (result != SQLITE_OK)
{
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
}
}
void obelisk::SuggestAction::insert(sqlite3* dbConnection)
{
if (dbConnection == nullptr)
{
throw obelisk::DatabaseException("database isn't open");
}
sqlite3_stmt* ppStmt = nullptr;
auto result = sqlite3_prepare_v2(dbConnection,
"INSERT INTO suggest_action (fact, true_action, false_action) VALUES (?, ?, ?)",
-1,
&ppStmt,
nullptr);
if (result != SQLITE_OK)
{
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
}
result = sqlite3_bind_int(ppStmt, 1, getFact().getId());
switch (result)
{
case SQLITE_OK :
break;
case SQLITE_TOOBIG :
throw obelisk::DatabaseSizeException();
break;
case SQLITE_RANGE :
throw obelisk::DatabaseRangeException();
break;
case SQLITE_NOMEM :
throw obelisk::DatabaseMemoryException();
break;
default :
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
break;
}
result = sqlite3_bind_int(ppStmt, 2, getTrueAction().getId());
switch (result)
{
case SQLITE_OK :
break;
case SQLITE_TOOBIG :
throw obelisk::DatabaseSizeException();
break;
case SQLITE_RANGE :
throw obelisk::DatabaseRangeException();
break;
case SQLITE_NOMEM :
throw obelisk::DatabaseMemoryException();
break;
default :
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
break;
}
result = sqlite3_bind_int(ppStmt, 3, getFalseAction().getId());
switch (result)
{
case SQLITE_OK :
break;
case SQLITE_TOOBIG :
throw obelisk::DatabaseSizeException();
break;
case SQLITE_RANGE :
throw obelisk::DatabaseRangeException();
break;
case SQLITE_NOMEM :
throw obelisk::DatabaseMemoryException();
break;
default :
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
break;
}
result = sqlite3_step(ppStmt);
switch (result)
{
case SQLITE_DONE :
setId((int) sqlite3_last_insert_rowid(dbConnection));
sqlite3_set_last_insert_rowid(dbConnection, 0);
break;
case SQLITE_CONSTRAINT :
throw obelisk::DatabaseConstraintException(sqlite3_errmsg(dbConnection));
case SQLITE_BUSY :
throw obelisk::DatabaseBusyException();
break;
case SQLITE_MISUSE :
throw obelisk::DatabaseMisuseException();
break;
default :
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
break;
}
result = sqlite3_finalize(ppStmt);
if (result != SQLITE_OK)
{
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
}
}
int& obelisk::SuggestAction::getId() int& obelisk::SuggestAction::getId()
{ {
return id_; return id_;

View File

@ -8,15 +8,43 @@
namespace obelisk namespace obelisk
{ {
/**
* @brief The SuggestAction model representas the actions to take depending
* on if the Fact is true or false.
*
*/
class SuggestAction class SuggestAction
{ {
private: private:
/**
* @brief The ID of the SuggestAction.
*
*/
int id_; int id_;
/**
* @brief The Fact to check the truth of.
*
*/
obelisk::Fact fact_; obelisk::Fact fact_;
/**
* @brief The Action to take if the Fact is true.
*
*/
obelisk::Action trueAction_; obelisk::Action trueAction_;
/**
* @brief The Action to take if the Fact is false.
*
*/
obelisk::Action falseAction_; obelisk::Action falseAction_;
public: public:
/**
* @brief Construct a new SuggestAction object.
*
*/
SuggestAction() : SuggestAction() :
id_(0), id_(0),
fact_(), fact_(),
@ -25,6 +53,11 @@ namespace obelisk
{ {
} }
/**
* @brief Construct a new SuggestAction object.
*
* @param[in] id The ID of the SuggestAction in the KnowledgeBase.
*/
SuggestAction(int id) : SuggestAction(int id) :
id_(id), id_(id),
fact_(), fact_(),
@ -33,6 +66,13 @@ namespace obelisk
{ {
} }
/**
* @brief Construct a new SuggestAction object.
*
* @param[in] fact The Fact.
* @param[in] trueAction The true Action.
* @param[in] falseAction The false Action.
*/
SuggestAction(obelisk::Fact fact, obelisk::Action trueAction, obelisk::Action falseAction) : SuggestAction(obelisk::Fact fact, obelisk::Action trueAction, obelisk::Action falseAction) :
id_(0), id_(0),
fact_(fact), fact_(fact),
@ -41,6 +81,14 @@ namespace obelisk
{ {
} }
/**
* @brief Construct a new SuggestAction object.
*
* @param[in] id The ID of the SuggestAction in the KnowledgeBase.
* @param[in] fact The Fact.
* @param[in] trueAction The true Action.
* @param[in] falseAction The false Action.
*/
SuggestAction(int id, obelisk::Fact fact, obelisk::Action trueAction, obelisk::Action falseAction) : SuggestAction(int id, obelisk::Fact fact, obelisk::Action trueAction, obelisk::Action falseAction) :
id_(id), id_(id),
fact_(fact), fact_(fact),
@ -49,19 +97,83 @@ namespace obelisk
{ {
} }
/**
* @brief Create the SuggestAction table in the database.
*
* @return const char* Returns the query used to create the table.
*/
static const char* createTable(); static const char* createTable();
/**
* @brief Get the ID of the SuggestAction.
*
* @return int& Returns the ID.
*/
int& getId(); int& getId();
/**
* @brief Set the ID of the SuggestAction.
*
* @param[in] id The new ID.
*/
void setId(int id); void setId(int id);
/**
* @brief Get the Fact object.
*
* @return obelisk::Fact& Returns the Fact.
*/
obelisk::Fact& getFact(); obelisk::Fact& getFact();
/**
* @brief Set the Fact object.
*
* @param[in] fact The new Fact.
*/
void setFact(obelisk::Fact fact); void setFact(obelisk::Fact fact);
/**
* @brief Get the true Action object.
*
* @return obelisk::Action& Returns the true Action.
*/
obelisk::Action& getTrueAction(); obelisk::Action& getTrueAction();
/**
* @brief Set the true Action object.
*
* @param[in] trueAction The new true Action.
*/
void setTrueAction(obelisk::Action trueAction); void setTrueAction(obelisk::Action trueAction);
/**
* @brief Get the false Action object.
*
* @return obelisk::Action& Returns the false Action.
*/
obelisk::Action& getFalseAction(); obelisk::Action& getFalseAction();
/**
* @brief Set the false Action object.
*
* @param[in] falseAction The new false Action.
*/
void setFalseAction(obelisk::Action falseAction); void setFalseAction(obelisk::Action falseAction);
/**
* @brief Select the SuggestAction from the KnowledgeBase by IDs of the
* sub-objects.
*
* @param[in] dbConnection The database connection to use.
*/
void selectById(sqlite3* dbConnection);
/**
* @brief Insert the SuggestAction into the KnowledgeBase.
*
* @param[in] dbConnection The database connection to use.
*/
void insert(sqlite3* dbConnection);
}; };
} // namespace obelisk } // namespace obelisk

View File

@ -16,7 +16,7 @@ namespace obelisk
{ {
private: private:
/** /**
* @brief The ID of the Verb in the knowledge base. * @brief The ID of the Verb in the KnowledgeBase.
* *
*/ */
int id_; int id_;

View File

@ -1,8 +1,6 @@
#include "include/obelisk.h" #include "include/obelisk.h"
#include "version.h" #include "version.h"
// TODO: Move the models to the library then link the compiler to the library
std::string obelisk::Obelisk::getVersion() std::string obelisk::Obelisk::getVersion()
{ {
return obelisk::version; return obelisk::version;

View File

@ -3,8 +3,7 @@ subdir('lib')
obelisk_sources = files( obelisk_sources = files(
'main.cpp', 'main.cpp',
'lexer.cpp', 'lexer.cpp',
'parser.cpp', 'parser.cpp'
'knowledge_base.cpp'
) )
sqlite3 = dependency('sqlite3') sqlite3 = dependency('sqlite3')

View File

@ -389,7 +389,7 @@ void obelisk::Parser::parseAction(obelisk::SuggestAction& suggestAction)
break; break;
} }
if (getLexer()->getIdentifier() == "or") if (getLexer()->getIdentifier() == "else")
{ {
getNextToken(); getNextToken();
getAction = true; getAction = true;
@ -406,7 +406,7 @@ void obelisk::Parser::parseAction(obelisk::SuggestAction& suggestAction)
suggestAction.setFact( suggestAction.setFact(
obelisk::Fact(obelisk::Entity(leftEntity), obelisk::Entity(rightEntity), obelisk::Verb(verb))); obelisk::Fact(obelisk::Entity(leftEntity), obelisk::Entity(rightEntity), obelisk::Verb(verb)));
suggestAction.setTrueAction(obelisk::Action(trueAction)); suggestAction.setTrueAction(obelisk::Action(trueAction));
suggestAction.setTrueAction(obelisk::Action(falseAction)); suggestAction.setFalseAction(obelisk::Action(falseAction));
} }
void obelisk::Parser::parseRule(std::vector<obelisk::Rule>& rules) void obelisk::Parser::parseRule(std::vector<obelisk::Rule>& rules)
@ -547,6 +547,8 @@ void obelisk::Parser::handleAction(std::unique_ptr<obelisk::KnowledgeBase>& kb)
insertEntity(kb, suggestAction.getFact().getRightEntity()); insertEntity(kb, suggestAction.getFact().getRightEntity());
insertVerb(kb, suggestAction.getFact().getVerb()); insertVerb(kb, suggestAction.getFact().getVerb());
insertFact(kb, suggestAction.getFact()); insertFact(kb, suggestAction.getFact());
insertAction(kb, suggestAction.getTrueAction());
insertAction(kb, suggestAction.getFalseAction());
// TODO: insert the actions, then insert the suggested action // TODO: insert the actions, then insert the suggested action
} }
@ -647,6 +649,23 @@ void obelisk::Parser::insertVerb(std::unique_ptr<obelisk::KnowledgeBase>& kb, ob
} }
} }
void obelisk::Parser::insertAction(std::unique_ptr<obelisk::KnowledgeBase>& kb, obelisk::Action& action)
{
std::vector<obelisk::Action> actions {action};
kb->addActions(actions);
action = std::move(actions.front());
// the id was not inserted, so check if it exists in the database
if (action.getId() == 0)
{
kb->getAction(action);
if (action.getId() == 0)
{
throw obelisk::ParserException("action could not be inserted into the database");
}
}
}
void obelisk::Parser::insertFact(std::unique_ptr<obelisk::KnowledgeBase>& kb, obelisk::Fact& fact) void obelisk::Parser::insertFact(std::unique_ptr<obelisk::KnowledgeBase>& kb, obelisk::Fact& fact)
{ {
std::vector<obelisk::Fact> facts {fact}; std::vector<obelisk::Fact> facts {fact};

View File

@ -63,6 +63,7 @@ namespace obelisk
void insertEntity(std::unique_ptr<obelisk::KnowledgeBase>& kb, obelisk::Entity& entity); void insertEntity(std::unique_ptr<obelisk::KnowledgeBase>& kb, obelisk::Entity& entity);
void insertVerb(std::unique_ptr<obelisk::KnowledgeBase>& kb, obelisk::Verb& verb); void insertVerb(std::unique_ptr<obelisk::KnowledgeBase>& kb, obelisk::Verb& verb);
void insertAction(std::unique_ptr<obelisk::KnowledgeBase>& kb, obelisk::Action& action);
void insertFact(std::unique_ptr<obelisk::KnowledgeBase>& kb, obelisk::Fact& fact); void insertFact(std::unique_ptr<obelisk::KnowledgeBase>& kb, obelisk::Fact& fact);
}; };