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 "models/action.h"
#include "models/entity.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 <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)
{
for (auto& fact : facts)
@ -150,9 +163,14 @@ void obelisk::KnowledgeBase::getVerb(obelisk::Verb& verb)
verb.selectByName(dbConnection_);
}
void obelisk::KnowledgeBase::getAction(obelisk::Action& action)
{
action.selectByName(dbConnection_);
}
void obelisk::KnowledgeBase::getFact(obelisk::Fact& fact)
{
fact.selectByName(dbConnection_);
fact.selectById(dbConnection_);
}
void obelisk::KnowledgeBase::getFloat(float& result1, float& result2, double var)

View File

@ -1,8 +1,11 @@
#ifndef OBELISK_KNOWLEDGE_BASE_H
#define OBELISK_KNOWLEDGE_BASE_H
#include "models/action.h"
#include "models/entity.h"
#include "models/fact.h"
#include "models/rule.h"
#include "models/suggest_action.h"
#include "models/verb.h"
#include <sqlite3.h>
@ -23,7 +26,7 @@ namespace obelisk
{
private:
/**
* @brief The filename of the opened knowledge base.
* @brief The filename of the opened KnowledgeBase.
*
*/
const char* filename_;
@ -61,7 +64,7 @@ namespace obelisk
*
* @param[in] filename The name of the file to save the knowledge
* 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);
@ -79,12 +82,12 @@ namespace obelisk
/**
* @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();
/**
* @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
* 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);
/**
* @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
* successful it will have a row ID, if not the ID will be 0.
*/
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.
*
@ -123,6 +134,14 @@ namespace obelisk
*/
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.
*

View File

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

View File

@ -1,4 +1,5 @@
#include "models/action.h"
#include "models/error.h"
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()
{
return id_;

View File

@ -1,6 +1,8 @@
#ifndef OBELISK_MODELS_ACTION_H
#define OBELISK_MODELS_ACTION_H
#include <sqlite3.h>
#include <string>
namespace obelisk
@ -14,7 +16,7 @@ namespace obelisk
{
private:
/**
* @brief The ID of the Action in the knowledge base.
* @brief The ID of the Action in the KnowledgeBase.
*
*/
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.
*/
@ -104,6 +106,22 @@ namespace obelisk
* @param[in] name The name of the Action.
*/
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

View File

@ -16,10 +16,11 @@ namespace obelisk
{
private:
/**
* @brief The ID of the Entity.
* @brief The ID of the Entity in the KnowledgeBase.
*
*/
int id_;
/**
* @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.
*/
@ -107,7 +108,7 @@ namespace obelisk
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.
*
* @param[in] dbConnection The database connection to use.
@ -115,7 +116,7 @@ namespace obelisk
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.
*
* @param[in] dbConnection The database connection to use.

View File

@ -6,77 +6,152 @@
namespace obelisk
{
/**
* @brief Exception thrown by database models.
*
*/
class DatabaseException : public std::exception
{
protected:
/**
* @brief The error message describing the exception.
*
*/
std::string errorMessage_;
public:
/**
* @brief Construct a new DatabaseException object.
*
*/
DatabaseException() :
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) :
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) :
errorMessage_(errorMessage)
{
}
/**
* @brief Retreive the exception message as a C type string.
*
* @return const char* The error message.
*/
virtual const char* what() const noexcept
{
return errorMessage_.c_str();
}
/**
* @brief Set the error message.
*
* @param[in] errorMessage The error message.
*/
virtual void setErrorMessage(const std::string errorMessage)
{
errorMessage_ = errorMessage;
}
};
/**
* @brief Exception thrown if the string or blob size exceeds sqlite's
* limits.
*
*/
class DatabaseSizeException : public obelisk::DatabaseException
{
public:
/**
* @brief Construct a new DatabaseSizeException object.
*
*/
DatabaseSizeException()
{
setErrorMessage("size of string or blob exceeds limits");
}
};
/**
* @brief Exception thrown if the index used it out of range.
*
*/
class DatabaseRangeException : public obelisk::DatabaseException
{
public:
/**
* @brief Construct a new DatabaseRangeException object.
*
*/
DatabaseRangeException()
{
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
{
public:
/**
* @brief Construct a new DatabaseMemoryException object.
*
*/
DatabaseMemoryException()
{
setErrorMessage("not enough memory for operation");
}
};
/**
* @brief Exception thrown if the database was busy.
*
*/
class DatabaseBusyException : public obelisk::DatabaseException
{
public:
/**
* @brief Construct a new DatabaseBusyException object.
*
*/
DatabaseBusyException()
{
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
{
public:
/**
* @brief Construct a new DatabaseMisuseException object.
*
*/
DatabaseMisuseException()
{
@ -84,14 +159,28 @@ namespace obelisk
}
};
/**
* @brief Exception thrown if a constraint was violated.
*
*/
class DatabaseConstraintException : public obelisk::DatabaseException
{
public:
/**
* @brief Construct a new DatabaseConstraintException object.
*
*/
DatabaseConstraintException()
{
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)
{
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)
{

View File

@ -9,16 +9,50 @@
namespace obelisk
{
/**
* @brief The Fact model represents truth in the releationship between two
* entities separated by a verb.
*
*/
class Fact
{
private:
/**
* @brief The ID of the Fact in the KnowledgeBase.
*
*/
int id_;
/**
* @brief The Entity from the left side of the expression.
*
*/
obelisk::Entity leftEntity_;
/**
* @brief The Entity from the right side of the expression.
*
*/
obelisk::Entity rightEntity_;
/**
* @brief The Verb that represents the relationship in the
* expression.
*
*/
obelisk::Verb verb_;
/**
* @brief Whether or not the fact is considered true or not.
*
*/
bool isTrue_;
public:
/**
* @brief Construct a new Fact object.
*
*/
Fact() :
id_(0),
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) :
id_(id),
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) :
id_(0),
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,
obelisk::Entity leftEntity,
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();
/**
* @brief Get the ID of the Fact
*
* @return int& Returns the ID.
*/
int& getId();
/**
* @brief Set the ID of the Fact.
*
* @param[in] id Set the ID of the Fact.
*/
void setId(int id);
/**
* @brief Get the left Entity object.
*
* @return Entity& The left Entity.
*/
Entity& getLeftEntity();
/**
* @brief Set the left Entity object.
*
* @param[in] leftEntity The left Entity to set.
*/
void setLeftEntity(obelisk::Entity leftEntity);
/**
* @brief Get the right Entity object.
*
* @return Entity& The right Entity.
*/
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();
/**
* @brief Set the Verb object.
*
* @param[in] verb The 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();
/**
* @brief Set the Fact as true or false.
*
* @param[in] isTrue Whether or not the Fact is true.
*/
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);
};
} // namespace obelisk

View File

@ -7,14 +7,36 @@
namespace obelisk
{
/**
* @brief The Rule model represents a truth relation between 2 Facts.
*
*/
class Rule
{
private:
/**
* @brief The ID of the Rule in the KnowledgeBase.
*
*/
int id_;
/**
* @brief The Fact that depends on the Fact reason being true.
*
*/
obelisk::Fact fact_;
/**
* @brief The Fact that makes the other Fact true or false.
*
*/
obelisk::Fact reason_;
public:
/**
* @brief Construct a new Rule object.
*
*/
Rule() :
id_(0),
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) :
id_(id),
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) :
id_(0),
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) :
id_(id),
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();
/**
* @brief Get the ID of the Rule.
*
* @return int& The ID.
*/
int& getId();
/**
* @brief Set the ID of the Rule.
*
* @param[in] id The ID.
*/
void setId(int id);
/**
* @brief Get the Fact object.
*
* @return obelisk::Fact& The Fact.
*/
obelisk::Fact& getFact();
/**
* @brief Set the Fact object.
*
* @param[in] fact The Fact.
*/
void setFact(obelisk::Fact fact);
/**
* @brief Get the reason Fact object.
*
* @return obelisk::Fact& The reason Fact.
*/
obelisk::Fact& getReason();
/**
* @brief Set the reason Fact object.
*
* @param[in] reason The reason Fact.
*/
void setReason(obelisk::Fact reason);
};
} // namespace obelisk

View File

@ -1,3 +1,4 @@
#include "models/error.h"
#include "models/suggest_action.h"
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()
{
return id_;

View File

@ -8,15 +8,43 @@
namespace obelisk
{
/**
* @brief The SuggestAction model representas the actions to take depending
* on if the Fact is true or false.
*
*/
class SuggestAction
{
private:
/**
* @brief The ID of the SuggestAction.
*
*/
int id_;
/**
* @brief The Fact to check the truth of.
*
*/
obelisk::Fact fact_;
/**
* @brief The Action to take if the Fact is true.
*
*/
obelisk::Action trueAction_;
/**
* @brief The Action to take if the Fact is false.
*
*/
obelisk::Action falseAction_;
public:
/**
* @brief Construct a new SuggestAction object.
*
*/
SuggestAction() :
id_(0),
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) :
id_(id),
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) :
id_(0),
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) :
id_(id),
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();
/**
* @brief Get the ID of the SuggestAction.
*
* @return int& Returns the ID.
*/
int& getId();
/**
* @brief Set the ID of the SuggestAction.
*
* @param[in] id The new ID.
*/
void setId(int id);
/**
* @brief Get the Fact object.
*
* @return obelisk::Fact& Returns the Fact.
*/
obelisk::Fact& getFact();
/**
* @brief Set the Fact object.
*
* @param[in] fact The new Fact.
*/
void setFact(obelisk::Fact fact);
/**
* @brief Get the true Action object.
*
* @return obelisk::Action& Returns the true Action.
*/
obelisk::Action& getTrueAction();
/**
* @brief Set the true Action object.
*
* @param[in] trueAction The new true Action.
*/
void setTrueAction(obelisk::Action trueAction);
/**
* @brief Get the false Action object.
*
* @return obelisk::Action& Returns the false Action.
*/
obelisk::Action& getFalseAction();
/**
* @brief Set the false Action object.
*
* @param[in] falseAction The new false Action.
*/
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

View File

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

View File

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

View File

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

View File

@ -389,7 +389,7 @@ void obelisk::Parser::parseAction(obelisk::SuggestAction& suggestAction)
break;
}
if (getLexer()->getIdentifier() == "or")
if (getLexer()->getIdentifier() == "else")
{
getNextToken();
getAction = true;
@ -406,7 +406,7 @@ void obelisk::Parser::parseAction(obelisk::SuggestAction& suggestAction)
suggestAction.setFact(
obelisk::Fact(obelisk::Entity(leftEntity), obelisk::Entity(rightEntity), obelisk::Verb(verb)));
suggestAction.setTrueAction(obelisk::Action(trueAction));
suggestAction.setTrueAction(obelisk::Action(falseAction));
suggestAction.setFalseAction(obelisk::Action(falseAction));
}
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());
insertVerb(kb, suggestAction.getFact().getVerb());
insertFact(kb, suggestAction.getFact());
insertAction(kb, suggestAction.getTrueAction());
insertAction(kb, suggestAction.getFalseAction());
// 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)
{
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 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);
};