feature/fact_knowledge_base #7

Merged
cromer merged 7 commits from feature/fact_knowledge_base into develop 2022-11-29 00:07:51 -03:00
11 changed files with 630 additions and 306 deletions
Showing only changes of commit 4a6086aac5 - Show all commits

View File

@ -1,13 +1,16 @@
#include "knowledge_base.h" #include "knowledge_base.h"
#include "models/action.h" #include "models/action.h"
#include "models/entity.h" #include "models/entity.h"
#include "models/error.h"
#include "models/fact.h" #include "models/fact.h"
#include "models/rule.h" #include "models/rule.h"
#include "models/suggest_action.h" #include "models/suggest_action.h"
#include "models/verb.h" #include "models/verb.h"
#include <cstring>
#include <filesystem> #include <filesystem>
#include <iostream> #include <iostream>
#include <string>
obelisk::KnowledgeBase::KnowledgeBase(const char* filename, int flags) obelisk::KnowledgeBase::KnowledgeBase(const char* filename, int flags)
{ {
@ -23,6 +26,8 @@ obelisk::KnowledgeBase::KnowledgeBase(const char* filename, int flags)
logSqliteError(result); logSqliteError(result);
} }
enableForeignKeys();
if (!dbExists) if (!dbExists)
{ {
createTable(obelisk::Action::createTable); createTable(obelisk::Action::createTable);
@ -42,16 +47,25 @@ obelisk::KnowledgeBase::~KnowledgeBase()
} }
} }
void obelisk::KnowledgeBase::createTable(std::function<const char*()> function) /**
* @brief Enable foreign key functionality in the open database.
*
* This must always be done when the connection is opened or it will not
* enforce the foreign key constraints.
*/
void obelisk::KnowledgeBase::enableForeignKeys()
{ {
char* tmp; char* errmsg;
auto result = sqlite3_exec(dbConnection_, function(), NULL, NULL, &tmp); int result = sqlite3_exec(dbConnection_,
"PRAGMA foreign_keys = ON;",
NULL,
NULL,
&errmsg);
if (result != SQLITE_OK) if (result != SQLITE_OK)
{ {
logSqliteError(result); logSqliteError(result);
if (tmp) if (errmsg)
{ {
std::string errmsg(tmp);
throw obelisk::KnowledgeBaseException(errmsg); throw obelisk::KnowledgeBaseException(errmsg);
} }
else else
@ -61,53 +75,103 @@ void obelisk::KnowledgeBase::createTable(std::function<const char*()> function)
} }
} }
// TODO: change these to throw errors instead of return int void obelisk::KnowledgeBase::createTable(std::function<const char*()> function)
int obelisk::KnowledgeBase::addEntities(std::vector<obelisk::Entity>& entities) {
char* errmsg;
int result = sqlite3_exec(dbConnection_, function(), NULL, NULL, &errmsg);
if (result != SQLITE_OK)
{
logSqliteError(result);
if (errmsg)
{
throw obelisk::KnowledgeBaseException(errmsg);
}
else
{
throw obelisk::KnowledgeBaseException();
}
}
}
void obelisk::KnowledgeBase::addEntities(std::vector<obelisk::Entity>& entities)
{ {
for (auto& entity : entities) for (auto& entity : entities)
{ {
entity.insertEntity(dbConnection_); try
{
entity.insertEntity(dbConnection_);
}
catch (obelisk::DatabaseException::ConstraintException& exception)
{
// ignore unique constraint error
if (std::strcmp(exception.what(),
"UNIQUE constraint failed: entity.name")
!= 0)
{
throw;
}
}
} }
return 0;
} }
int obelisk::KnowledgeBase::addVerbs(std::vector<obelisk::Verb>& verbs) void obelisk::KnowledgeBase::addVerbs(std::vector<obelisk::Verb>& verbs)
{ {
for (auto& verb : verbs) for (auto& verb : verbs)
{ {
verb.insertVerb(dbConnection_); try
{
verb.insertVerb(dbConnection_);
}
catch (obelisk::DatabaseException::ConstraintException& exception)
{
// ignore unique constraint error
if (std::strcmp(exception.what(),
"UNIQUE constraint failed: verb.name")
!= 0)
{
throw;
}
}
} }
return 0;
} }
int 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)
{ {
fact.insertFact(dbConnection_); try
{
fact.insertFact(dbConnection_);
}
catch (obelisk::DatabaseException::ConstraintException& exception)
{
// ignore unique constraint error
if (std::strcmp(exception.what(),
"UNIQUE constraint failed: fact.left_entity, fact.right_entity, fact.verb")
!= 0)
{
throw;
}
}
} }
return 0;
} }
int obelisk::KnowledgeBase::getEntity(obelisk::Entity& entity) void obelisk::KnowledgeBase::getEntity(obelisk::Entity& entity)
{ {
entity.selectEntity(dbConnection_); entity.selectEntity(dbConnection_);
return 0;
} }
int obelisk::KnowledgeBase::getVerb(obelisk::Verb& verb) void obelisk::KnowledgeBase::getVerb(obelisk::Verb& verb)
{ {
verb.selectVerb(dbConnection_); verb.selectVerb(dbConnection_);
return 0;
} }
int obelisk::KnowledgeBase::getFact(obelisk::Fact& fact) void obelisk::KnowledgeBase::getFact(obelisk::Fact& fact)
{ {
fact.selectFact(dbConnection_); fact.selectFact(dbConnection_);
return 0;
} }
// TODO: log files? // TODO: log files? or just throw an error?
void obelisk::KnowledgeBase::logSqliteError(int result) void obelisk::KnowledgeBase::logSqliteError(int result)
{ {
std::cout << sqlite3_errstr(result) << std::endl; std::cout << sqlite3_errstr(result) << std::endl;

View File

@ -24,6 +24,7 @@ namespace obelisk
int flags_; int flags_;
void logSqliteError(int result); void logSqliteError(int result);
void enableForeignKeys();
void createTable(std::function<const char*()> function); void createTable(std::function<const char*()> function);
public: public:
@ -37,13 +38,13 @@ namespace obelisk
~KnowledgeBase(); ~KnowledgeBase();
int addEntities(std::vector<obelisk::Entity>& entities); void addEntities(std::vector<obelisk::Entity>& entities);
int addVerbs(std::vector<obelisk::Verb>& verbs); void addVerbs(std::vector<obelisk::Verb>& verbs);
int addFacts(std::vector<obelisk::Fact>& facts); void addFacts(std::vector<obelisk::Fact>& facts);
int getEntity(obelisk::Entity& entity); void getEntity(obelisk::Entity& entity);
int getVerb(obelisk::Verb& verb); void getVerb(obelisk::Verb& verb);
int getFact(obelisk::Fact& fact); void getFact(obelisk::Fact& fact);
void getDouble(double& result, float var1, float var2); void getDouble(double& result, float var1, float var2);
void getFloat(float& result1, float& result2, double var); void getFloat(float& result1, float& result2, double var);

View File

@ -1,4 +1,5 @@
#include "models/entity.h" #include "models/entity.h"
#include "models/error.h"
const char* obelisk::Entity::createTable() const char* obelisk::Entity::createTable()
{ {
@ -11,118 +12,139 @@ const char* obelisk::Entity::createTable()
)"; )";
} }
int obelisk::Entity::selectEntity(sqlite3* dbConnection) void obelisk::Entity::selectEntity(sqlite3* dbConnection)
{ {
// TODO: check if database is open if (dbConnection == nullptr)
{
throw obelisk::DatabaseException("database isn't open");
}
sqlite3_stmt* ppStmt = nullptr; sqlite3_stmt* ppStmt = nullptr;
const char* pzTail = nullptr;
auto result = sqlite3_prepare_v2(dbConnection, auto result = sqlite3_prepare_v2(dbConnection,
"SELECT id, name FROM entity WHERE name=?;", "SELECT id, name FROM entity WHERE name=?",
-1, -1,
&ppStmt, &ppStmt,
&pzTail); nullptr);
if (result != SQLITE_OK) if (result != SQLITE_OK)
{ {
// TODO: something went wrong throw an error throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
} }
if (pzTail != nullptr) result = sqlite3_bind_text(ppStmt, 1, getName().c_str(), -1, SQLITE_STATIC);
switch (result)
{ {
// TODO: Something was not used... throw an error case SQLITE_OK :
} break;
case SQLITE_TOOBIG :
result throw obelisk::DatabaseException::SizeException();
= sqlite3_bind_text(ppStmt, 1, getName().c_str(), -1, SQLITE_TRANSIENT); break;
if (result != SQLITE_OK) case SQLITE_RANGE :
{ throw obelisk::DatabaseException::RangeException();
// TODO: Something is wrong... throw an error break;
case SQLITE_NOMEM :
throw obelisk::DatabaseException::MemoryException();
break;
default :
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
break;
} }
result = sqlite3_step(ppStmt); result = sqlite3_step(ppStmt);
if (result != SQLITE_DONE) switch (result)
{ {
// TODO: Something is wrong... throw an error 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::DatabaseException::BusyException();
break;
case SQLITE_MISUSE :
throw obelisk::DatabaseException::MisuseException();
break;
default :
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
break;
} }
if (result == SQLITE_ROW) result = sqlite3_finalize(ppStmt);
{
setId(sqlite3_column_int(ppStmt, 0));
setName((char*) sqlite3_column_text(ppStmt, 1));
result = sqlite3_finalize(ppStmt); if (result != SQLITE_OK)
if (result != SQLITE_OK)
{
// TODO: Something is wrong... throw an error
}
return 0;
}
else
{ {
result = sqlite3_finalize(ppStmt); throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
if (result != SQLITE_OK)
{
// TODO: Something is wrong... throw an error
}
return 0;
} }
} }
int obelisk::Entity::insertEntity(sqlite3* dbConnection) void obelisk::Entity::insertEntity(sqlite3* dbConnection)
{ {
// TODO: check if database is open if (dbConnection == nullptr)
/*selectEntity(dbConnection);
if (getId() != 0)
{ {
// TODO: already exists in database, throw an error? Or skip past it? throw obelisk::DatabaseException("database isn't open");
return -1;
}*/
sqlite3_stmt* ppStmt = nullptr;
const char* pzTail = nullptr;
auto result = sqlite3_prepare_v2(dbConnection,
"INSERT INTO entity (name) VALUES (?);",
-1,
&ppStmt,
&pzTail);
if (result != SQLITE_OK)
{
// TODO: something went wrong throw an error
} }
if (pzTail != nullptr) sqlite3_stmt* ppStmt = nullptr;
auto result = sqlite3_prepare_v2(dbConnection,
"INSERT INTO entity (name) VALUES (?)",
-1,
&ppStmt,
nullptr);
if (result != SQLITE_OK)
{ {
// TODO: Something was not used... throw an error throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
} }
result result
= sqlite3_bind_text(ppStmt, 1, getName().c_str(), -1, SQLITE_TRANSIENT); = sqlite3_bind_text(ppStmt, 1, getName().c_str(), -1, SQLITE_TRANSIENT);
if (result != SQLITE_OK) switch (result)
{ {
// TODO: Something is wrong... throw an error case SQLITE_OK :
break;
case SQLITE_TOOBIG :
throw obelisk::DatabaseException::SizeException();
break;
case SQLITE_RANGE :
throw obelisk::DatabaseException::RangeException();
break;
case SQLITE_NOMEM :
throw obelisk::DatabaseException::MemoryException();
break;
default :
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
break;
} }
result = sqlite3_step(ppStmt); result = sqlite3_step(ppStmt);
if (result != SQLITE_DONE) switch (result)
{ {
// TODO: Something is wrong... throw an error case SQLITE_DONE :
setId((int) sqlite3_last_insert_rowid(dbConnection));
sqlite3_set_last_insert_rowid(dbConnection, 0);
break;
case SQLITE_CONSTRAINT :
throw obelisk::DatabaseException::ConstraintException(
sqlite3_errmsg(dbConnection));
case SQLITE_BUSY :
throw obelisk::DatabaseException::BusyException();
break;
case SQLITE_MISUSE :
throw obelisk::DatabaseException::MisuseException();
break;
default :
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
break;
} }
else
{
setId((int) sqlite3_last_insert_rowid(dbConnection));
}
sqlite3_set_last_insert_rowid(dbConnection, 0);
result = sqlite3_finalize(ppStmt); result = sqlite3_finalize(ppStmt);
if (result != SQLITE_OK) if (result != SQLITE_OK)
{ {
// TODO: Something is wrong... throw an error throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
} }
return 0;
} }
int& obelisk::Entity::getId() int& obelisk::Entity::getId()

View File

@ -46,8 +46,8 @@ namespace obelisk
std::string& getName(); std::string& getName();
void setName(std::string name); void setName(std::string name);
int selectEntity(sqlite3* dbConnection); void selectEntity(sqlite3* dbConnection);
int insertEntity(sqlite3* dbConnection); void insertEntity(sqlite3* dbConnection);
}; };
} // namespace obelisk } // namespace obelisk

146
src/models/error.h Normal file
View File

@ -0,0 +1,146 @@
#ifndef OBELISK_MODELS_ERROR_H
#define OBELISK_MODELS_ERROR_H
#include <exception>
#include <string>
namespace obelisk
{
class DatabaseException : public std::exception
{
private:
const std::string errorMessage_;
public:
DatabaseException() :
errorMessage_("an unknown error ocurred")
{
}
DatabaseException(const int errorCode) :
errorMessage_(
"database error " + std::to_string(errorCode) + " ocurred")
{
}
DatabaseException(const std::string& errorMessage) :
errorMessage_(errorMessage)
{
}
const char* what() const noexcept
{
return errorMessage_.c_str();
}
class SizeException : public std::exception
{
private:
const std::string errorMessage_;
public:
SizeException() :
errorMessage_("size of string or blob exceeds limits")
{
}
const char* what() const noexcept
{
return errorMessage_.c_str();
}
};
class RangeException : public std::exception
{
private:
const std::string errorMessage_;
public:
RangeException() :
errorMessage_("parameter index is out of range")
{
}
const char* what() const noexcept
{
return errorMessage_.c_str();
}
};
class MemoryException : public std::exception
{
private:
const std::string errorMessage_;
public:
MemoryException() :
errorMessage_("not enough memory for operation")
{
}
const char* what() const noexcept
{
return errorMessage_.c_str();
}
};
class BusyException : public std::exception
{
private:
const std::string errorMessage_;
public:
BusyException() :
errorMessage_(
"database was busy and operation not performed")
{
}
const char* what() const noexcept
{
return errorMessage_.c_str();
}
};
class MisuseException : public std::exception
{
private:
const std::string errorMessage_;
public:
MisuseException() :
errorMessage_("misuse of the database routine")
{
}
const char* what() const noexcept
{
return errorMessage_.c_str();
}
};
class ConstraintException : public std::exception
{
private:
const std::string errorMessage_;
public:
ConstraintException() :
errorMessage_("a constraint exception occurred")
{
}
ConstraintException(const std::string& errorMessage) :
errorMessage_(errorMessage)
{
}
const char* what() const noexcept
{
return errorMessage_.c_str();
}
};
};
} // namespace obelisk
#endif

View File

@ -1,3 +1,4 @@
#include "models/error.h"
#include "models/fact.h" #include "models/fact.h"
const char* obelisk::Fact::createTable() const char* obelisk::Fact::createTable()
@ -9,6 +10,7 @@ const char* obelisk::Fact::createTable()
"right_entity" INTEGER NOT NULL, "right_entity" INTEGER NOT NULL,
"verb" INTEGER NOT NULL, "verb" INTEGER NOT NULL,
PRIMARY KEY("id" AUTOINCREMENT), PRIMARY KEY("id" AUTOINCREMENT),
UNIQUE("left_entity", "right_entity", "verb")
FOREIGN KEY("verb") REFERENCES "verb"("id") ON DELETE RESTRICT, FOREIGN KEY("verb") REFERENCES "verb"("id") ON DELETE RESTRICT,
FOREIGN KEY("right_entity") REFERENCES "entity"("id") ON DELETE RESTRICT, FOREIGN KEY("right_entity") REFERENCES "entity"("id") ON DELETE RESTRICT,
FOREIGN KEY("left_entity") REFERENCES "entity"("id") ON DELETE RESTRICT FOREIGN KEY("left_entity") REFERENCES "entity"("id") ON DELETE RESTRICT
@ -16,146 +18,214 @@ const char* obelisk::Fact::createTable()
)"; )";
} }
int obelisk::Fact::selectFact(sqlite3* dbConnection) void obelisk::Fact::selectFact(sqlite3* dbConnection)
{ {
// TODO: check if database is open if (dbConnection == nullptr)
sqlite3_stmt* ppStmt = nullptr;
const char* pzTail = nullptr;
auto result = sqlite3_prepare_v2(dbConnection,
"SELECT id, left_entity, right_entity, verb FROM fact WHERE (left_entity=? AND right_entity=? AND verb=?);",
-1,
&ppStmt,
&pzTail);
if (result != SQLITE_OK)
{ {
// TODO: something went wrong throw an error throw obelisk::DatabaseException("database isn't open");
} }
if (pzTail != nullptr) sqlite3_stmt* ppStmt = nullptr;
auto result = sqlite3_prepare_v2(dbConnection,
"SELECT id, left_entity, right_entity, verb FROM fact WHERE (left_entity=? AND right_entity=? AND verb=?)",
-1,
&ppStmt,
nullptr);
if (result != SQLITE_OK)
{ {
// TODO: Something was not used... throw an error throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
} }
result = sqlite3_bind_int(ppStmt, 1, getLeftEntity().getId()); result = sqlite3_bind_int(ppStmt, 1, getLeftEntity().getId());
if (result != SQLITE_OK) switch (result)
{ {
// TODO: Something is wrong... throw an error case SQLITE_OK :
break;
case SQLITE_TOOBIG :
throw obelisk::DatabaseException::SizeException();
break;
case SQLITE_RANGE :
throw obelisk::DatabaseException::RangeException();
break;
case SQLITE_NOMEM :
throw obelisk::DatabaseException::MemoryException();
break;
default :
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
break;
} }
result = sqlite3_bind_int(ppStmt, 2, getRightEntity().getId()); result = sqlite3_bind_int(ppStmt, 2, getRightEntity().getId());
if (result != SQLITE_OK) switch (result)
{ {
// TODO: Something is wrong... throw an error case SQLITE_OK :
break;
case SQLITE_TOOBIG :
throw obelisk::DatabaseException::SizeException();
break;
case SQLITE_RANGE :
throw obelisk::DatabaseException::RangeException();
break;
case SQLITE_NOMEM :
throw obelisk::DatabaseException::MemoryException();
break;
default :
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
break;
} }
result = sqlite3_bind_int(ppStmt, 3, getVerb().getId()); result = sqlite3_bind_int(ppStmt, 3, getVerb().getId());
if (result != SQLITE_OK) switch (result)
{ {
// TODO: Something is wrong... throw an error case SQLITE_OK :
break;
case SQLITE_TOOBIG :
throw obelisk::DatabaseException::SizeException();
break;
case SQLITE_RANGE :
throw obelisk::DatabaseException::RangeException();
break;
case SQLITE_NOMEM :
throw obelisk::DatabaseException::MemoryException();
break;
default :
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
break;
} }
result = sqlite3_step(ppStmt); result = sqlite3_step(ppStmt);
if (result != SQLITE_DONE) switch (result)
{ {
// TODO: Something is wrong... throw an error case SQLITE_DONE :
// no rows in the database
break;
case SQLITE_ROW :
setId(sqlite3_column_int(ppStmt, 0));
getLeftEntity().setId(sqlite3_column_int(ppStmt, 1));
getRightEntity().setId(sqlite3_column_int(ppStmt, 2));
getVerb().setId(sqlite3_column_int(ppStmt, 3));
break;
case SQLITE_BUSY :
throw obelisk::DatabaseException::BusyException();
break;
case SQLITE_MISUSE :
throw obelisk::DatabaseException::MisuseException();
break;
default :
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
break;
} }
if (result == SQLITE_ROW)
{
setId(sqlite3_column_int(ppStmt, 0));
getLeftEntity().setId(sqlite3_column_int(ppStmt, 1));
getRightEntity().setId(sqlite3_column_int(ppStmt, 2));
getVerb().setId(sqlite3_column_int(ppStmt, 3));
result = sqlite3_finalize(ppStmt);
if (result != SQLITE_OK)
{
// TODO: Something is wrong... throw an error
}
return 0;
}
else
{
result = sqlite3_finalize(ppStmt);
if (result != SQLITE_OK)
{
// TODO: Something is wrong... throw an error
}
return 0;
}
}
int obelisk::Fact::insertFact(sqlite3* dbConnection)
{
// TODO: make sure database is open
// check if the fact id exists, based on the ids of the entities and verb
/*selectFact(dbConnection);
if (getId() != 0)
{
// TODO: Verb is already in database, throw an error? Or just skip it?
return -1;
}*/
// TODO: verify that verbId, leftEntityId, and rightEntityId are not 0
sqlite3_stmt* ppStmt = nullptr;
const char* pzTail = nullptr;
auto result = sqlite3_prepare_v2(dbConnection,
"INSERT INTO fact (left_entity, right_entity, verb) VALUES (?, ?, ?);",
-1,
&ppStmt,
&pzTail);
if (result != SQLITE_OK)
{
// TODO: something went wrong throw an error
}
if (pzTail != nullptr)
{
// TODO: Something was not used... throw an error
}
result = sqlite3_bind_int(ppStmt, 1, getLeftEntity().getId());
if (result != SQLITE_OK)
{
// TODO: Something is wrong... throw an error
}
result = sqlite3_bind_int(ppStmt, 2, getRightEntity().getId());
if (result != SQLITE_OK)
{
// TODO: Something is wrong... throw an error
}
result = sqlite3_bind_int(ppStmt, 3, getVerb().getId());
if (result != SQLITE_OK)
{
// TODO: Something is wrong... throw an error
}
result = sqlite3_step(ppStmt);
if (result != SQLITE_DONE)
{
// TODO: Something is wrong... throw an error
}
else
{
setId((int) sqlite3_last_insert_rowid(dbConnection));
}
sqlite3_set_last_insert_rowid(dbConnection, 0);
result = sqlite3_finalize(ppStmt); result = sqlite3_finalize(ppStmt);
if (result != SQLITE_OK) if (result != SQLITE_OK)
{ {
// TODO: Something is wrong... throw an error throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
}
}
void obelisk::Fact::insertFact(sqlite3* dbConnection)
{
if (dbConnection == nullptr)
{
throw obelisk::DatabaseException("database isn't open");
} }
return 0; sqlite3_stmt* ppStmt = nullptr;
auto result = sqlite3_prepare_v2(dbConnection,
"INSERT INTO fact (left_entity, right_entity, verb) VALUES (?, ?, ?)",
-1,
&ppStmt,
nullptr);
if (result != SQLITE_OK)
{
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
}
result = sqlite3_bind_int(ppStmt, 1, getLeftEntity().getId());
switch (result)
{
case SQLITE_OK :
break;
case SQLITE_TOOBIG :
throw obelisk::DatabaseException::SizeException();
break;
case SQLITE_RANGE :
throw obelisk::DatabaseException::RangeException();
break;
case SQLITE_NOMEM :
throw obelisk::DatabaseException::MemoryException();
break;
default :
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
break;
}
result = sqlite3_bind_int(ppStmt, 2, getRightEntity().getId());
switch (result)
{
case SQLITE_OK :
break;
case SQLITE_TOOBIG :
throw obelisk::DatabaseException::SizeException();
break;
case SQLITE_RANGE :
throw obelisk::DatabaseException::RangeException();
break;
case SQLITE_NOMEM :
throw obelisk::DatabaseException::MemoryException();
break;
default :
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
break;
}
result = sqlite3_bind_int(ppStmt, 3, getVerb().getId());
switch (result)
{
case SQLITE_OK :
break;
case SQLITE_TOOBIG :
throw obelisk::DatabaseException::SizeException();
break;
case SQLITE_RANGE :
throw obelisk::DatabaseException::RangeException();
break;
case SQLITE_NOMEM :
throw obelisk::DatabaseException::MemoryException();
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::DatabaseException::ConstraintException(
sqlite3_errmsg(dbConnection));
case SQLITE_BUSY :
throw obelisk::DatabaseException::BusyException();
break;
case SQLITE_MISUSE :
throw obelisk::DatabaseException::MisuseException();
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::Fact::getId() int& obelisk::Fact::getId()

View File

@ -69,8 +69,8 @@ namespace obelisk
Verb& getVerb(); Verb& getVerb();
void setVerb(obelisk::Verb verb); void setVerb(obelisk::Verb verb);
int selectFact(sqlite3* dbConnection); void selectFact(sqlite3* dbConnection);
int insertFact(sqlite3* dbConnection); void insertFact(sqlite3* dbConnection);
}; };
} // namespace obelisk } // namespace obelisk

View File

@ -8,6 +8,7 @@ const char* obelisk::Rule::createTable()
"fact" INTEGER NOT NULL, "fact" INTEGER NOT NULL,
"reason" INTEGER NOT NULL CHECK("reason" != "fact"), "reason" INTEGER NOT NULL CHECK("reason" != "fact"),
PRIMARY KEY("id" AUTOINCREMENT), PRIMARY KEY("id" AUTOINCREMENT),
UNIQUE("fact", "reason"),
FOREIGN KEY("fact") REFERENCES "fact"("id") ON DELETE RESTRICT, FOREIGN KEY("fact") REFERENCES "fact"("id") ON DELETE RESTRICT,
FOREIGN KEY("reason") REFERENCES "fact"("id") ON DELETE RESTRICT FOREIGN KEY("reason") REFERENCES "fact"("id") ON DELETE RESTRICT
); );

View File

@ -9,6 +9,7 @@ const char* obelisk::SuggestAction::createTable()
"true_action" INTEGER NOT NULL, "true_action" INTEGER NOT NULL,
"false_action" INTEGER NOT NULL, "false_action" INTEGER NOT NULL,
PRIMARY KEY("id" AUTOINCREMENT), PRIMARY KEY("id" AUTOINCREMENT),
UNIQUE("fact", "true_action", "false_action"),
FOREIGN KEY("fact") REFERENCES "fact"("id") ON DELETE RESTRICT, FOREIGN KEY("fact") REFERENCES "fact"("id") ON DELETE RESTRICT,
FOREIGN KEY("true_action") REFERENCES "action"("id") ON DELETE RESTRICT, FOREIGN KEY("true_action") REFERENCES "action"("id") ON DELETE RESTRICT,
FOREIGN KEY("false_action") REFERENCES "action"("id") ON DELETE RESTRICT FOREIGN KEY("false_action") REFERENCES "action"("id") ON DELETE RESTRICT

View File

@ -1,3 +1,4 @@
#include "models/error.h"
#include "models/verb.h" #include "models/verb.h"
#include <iostream> #include <iostream>
@ -13,119 +14,137 @@ const char* obelisk::Verb::createTable()
)"; )";
} }
int obelisk::Verb::selectVerb(sqlite3* dbConnection) void obelisk::Verb::selectVerb(sqlite3* dbConnection)
{ {
// TODO: check if database is open if (dbConnection == nullptr)
{
throw obelisk::DatabaseException("database isn't open");
}
sqlite3_stmt* ppStmt = nullptr; sqlite3_stmt* ppStmt = nullptr;
const char* pzTail = nullptr;
auto result = sqlite3_prepare_v2(dbConnection, auto result = sqlite3_prepare_v2(dbConnection,
"SELECT id, name FROM verb WHERE name=?;", "SELECT id, name FROM verb WHERE name=?",
-1, -1,
&ppStmt, &ppStmt,
&pzTail); nullptr);
if (result != SQLITE_OK) if (result != SQLITE_OK)
{ {
// TODO: something went wrong throw an error throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
} }
if (pzTail != nullptr) result = sqlite3_bind_text(ppStmt, 1, getName().c_str(), -1, SQLITE_STATIC);
switch (result)
{ {
// TODO: Something was not used... throw an error case SQLITE_OK :
} break;
case SQLITE_TOOBIG :
result throw obelisk::DatabaseException::SizeException();
= sqlite3_bind_text(ppStmt, 1, getName().c_str(), -1, SQLITE_TRANSIENT); break;
if (result != SQLITE_OK) case SQLITE_RANGE :
{ throw obelisk::DatabaseException::RangeException();
// TODO: Something is wrong... throw an error break;
case SQLITE_NOMEM :
throw obelisk::DatabaseException::MemoryException();
break;
default :
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
break;
} }
result = sqlite3_step(ppStmt); result = sqlite3_step(ppStmt);
if (result != SQLITE_DONE) switch (result)
{ {
// TODO: Something is wrong... throw an error 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::DatabaseException::BusyException();
break;
case SQLITE_MISUSE :
throw obelisk::DatabaseException::MisuseException();
break;
default :
throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
break;
} }
if (result == SQLITE_ROW)
{
setId(sqlite3_column_int(ppStmt, 0));
setName((char*) sqlite3_column_text(ppStmt, 1));
result = sqlite3_finalize(ppStmt);
if (result != SQLITE_OK)
{
// TODO: Something is wrong... throw an error
}
return 0;
}
else
{
result = sqlite3_finalize(ppStmt);
if (result != SQLITE_OK)
{
// TODO: Something is wrong... throw an error
}
return 0;
}
}
int obelisk::Verb::insertVerb(sqlite3* dbConnection)
{
// TODO: make sure database is open
/*selectVerb(dbConnection);
if (getId() != 0)
{
// TODO: Verb is already in database, throw an error? Or just skip it?
return -1;
}*/
sqlite3_stmt* ppStmt = nullptr;
const char* pzTail = nullptr;
auto result = sqlite3_prepare_v2(dbConnection,
"INSERT INTO verb (name) VALUES (?);",
-1,
&ppStmt,
&pzTail);
if (result != SQLITE_OK)
{
// TODO: something went wrong throw an error
}
if (pzTail != nullptr)
{
// TODO: Something was not used... throw an error
}
result
= sqlite3_bind_text(ppStmt, 1, getName().c_str(), -1, SQLITE_TRANSIENT);
if (result != SQLITE_OK)
{
// TODO: Something is wrong... throw an error
}
result = sqlite3_step(ppStmt);
if (result != SQLITE_DONE)
{
// TODO: Something is wrong... throw an error
}
else
{
setId((int) sqlite3_last_insert_rowid(dbConnection));
}
sqlite3_set_last_insert_rowid(dbConnection, 0);
result = sqlite3_finalize(ppStmt); result = sqlite3_finalize(ppStmt);
if (result != SQLITE_OK) if (result != SQLITE_OK)
{ {
// TODO: Something is wrong... throw an error throw obelisk::DatabaseException(sqlite3_errmsg(dbConnection));
}
}
void obelisk::Verb::insertVerb(sqlite3* dbConnection)
{
if (dbConnection == nullptr)
{
throw obelisk::DatabaseException("database isn't open");
} }
return 0; sqlite3_stmt* ppStmt = nullptr;
auto result = sqlite3_prepare_v2(dbConnection,
"INSERT INTO verb (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::DatabaseException::SizeException();
break;
case SQLITE_RANGE :
throw obelisk::DatabaseException::RangeException();
break;
case SQLITE_NOMEM :
throw obelisk::DatabaseException::MemoryException();
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::DatabaseException::ConstraintException(
sqlite3_errmsg(dbConnection));
case SQLITE_BUSY :
throw obelisk::DatabaseException::BusyException();
break;
case SQLITE_MISUSE :
throw obelisk::DatabaseException::MisuseException();
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::Verb::getId() int& obelisk::Verb::getId()

View File

@ -46,8 +46,8 @@ namespace obelisk
std::string& getName(); std::string& getName();
void setName(std::string name); void setName(std::string name);
int selectVerb(sqlite3* dbConnection); void selectVerb(sqlite3* dbConnection);
int insertVerb(sqlite3* dbConnection); void insertVerb(sqlite3* dbConnection);
}; };
} // namespace obelisk } // namespace obelisk