Skip to content

Instantly share code, notes, and snippets.

@elja
Created June 1, 2016 10:04
Show Gist options
  • Save elja/baedecdae971514c4053abd78424c461 to your computer and use it in GitHub Desktop.
Save elja/baedecdae971514c4053abd78424c461 to your computer and use it in GitHub Desktop.
class Repository {
protected:
SQLManager *dbManager = NULL;
virtual string _getTableName() = 0;
virtual vector<string> _getColumnNames() = 0;
virtual bool _insertRecord(RepositoryObject *object) = 0;
virtual bool _updateRecord(RepositoryObject *object) = 0;
virtual void _createSchema() = 0;
virtual RepositoryObject* _initNewRecord() = 0;
virtual bool _removeRecord(RepositoryObject *object) {
SQLQuery *query = dbManager->prepareQuery("DELETE FROM " + _getTableName() + " WHERE id=?;");
query->setIntParam(1, object->getID());
return _execSQL(query);
};
//преобразовываем матрицу (массив сторок, каждая строка это массив коллонок) из базы данных
//в список объектов, т.е. массив строк, но уже вместо массива коллонок просто объект с аттрибутами внутри
vector<RepositoryObject*> fillInObjects(vector<vector<string> > sqlResults) {
//получаем список имен коллонок в текущем хранилище (для пациэнтов одни колонки, для пользователей другие, у каждого хранилища своя схема и свои списки колонок)
vector<string> colNames = _getColumnNames();
//инициализируем массив в котором буду хранится наши объекты с аттрибутами
vector<RepositoryObject*> records;
//получаем сколько у нас всего строк пришло из базы данных
int rows = sqlResults.size();
//цикл, идем по всем строкам
for (int row = 0; row < rows; row++) {
//для каждой строки создаем новый объект с аттрибутами
//тут используется полиморфизм, каждое хранилище может создать объект своего типа, но потом он приводится с базовому типу
//так хранилище пользователей инициализируем объект User, хранилище пациентов - Patient, а потом они приводятся к базовому для них типу RepositoryObject
RepositoryObject *record = _initNewRecord();
//получаем массив колонок по текущему индексу строки из базы данных
vector<string> colValues = sqlResults[row];
//узнаем сколько всего у нас колонк
int cols = colValues.size();
//идем по каждой колонке
for (int col = 0; col < cols; col++) {
//вызываем setAttribute у User или Patient через полиморфизм (через виртуальный метод)
//аргументы метода это будет название колонки и значение
//например для пациэнтов это будет типа так: record->setAttribute('age', '21')
record->setAttribute(colNames[col].c_str(), colValues[col].c_str());
}
//когда прошли по всем колонкам мы заполнили объект всеми аттрибутами из базы данных
//пихаем его в наш массив объектов с аттрибутами
records.push_back(record);
}
//готово, выходим
return records;
}
bool _insertSQL(RepositoryObject *object, SQLQuery *query) {
if (_execSQL(query)) {
object->setID(dbManager->getLastInsertedID());
return true;
}
return false;
}
bool _execSQL(SQLQuery *query) {
try {
int result = dbManager->execQuery(query);
if (result == SQL_SUCCESS) {
return true;
}
}
catch(const runtime_error& ex) {
cout << endl << "Exec query error: " << ex.what();
}
return false;
}
void _createSQLSchema(string sqlSchema) {
int createResult = dbManager->exec(sqlSchema);
if (createResult != SQL_SUCCESS) {
fprintf(stderr, "SQL ERROR: %s\n", dbManager->getCurrentError());
throw runtime_error("Can't create SQL schema\n");
}
}
public:
Repository(SQLManager *db) {
this->dbManager = db;
}
~Repository() {
}
vector<RepositoryObject*> getAll() {
string queryStr = "SELECT * FROM " + _getTableName() + ";";
SQLQuery *query = dbManager->prepareQuery(queryStr.c_str());
return fillInObjects(dbManager->selectQuery(query));
}
RepositoryObject* getById(const row_id id) {
string queryStr = "SELECT * FROM " + _getTableName() + " WHERE ID = ?;";
SQLQuery *query = dbManager->prepareQuery(queryStr.c_str());
query->setIntParam(1, id);
vector<RepositoryObject*> objects = fillInObjects(dbManager->selectQuery(query));
return objects.size() == 1 ? objects[0] : nullptr;
}
bool remove(RepositoryObject *object) {
if (!object->isNewRecord()) {
return _removeRecord(object);
}
return false;
}
//принимаем объект приведенный к базовому типу (вообще весь этот класс работает только с объектами базового типа)
//все это называется полиморфизм, когда мы работаем как бы с черным ящиком, внутри которого своя реализация методов
//мы только знает интерфейс этого черного ящика - т.е. какие методы у него есть и как их можно вызвать
bool save(RepositoryObject *object) {
// проверям валидный ли объект, реализация isValid ложится на плечи какого-то из классов, например User, Patient
// вот тут как раз тот случай где мы знаем что есть такой метод, но реализация находится где-то внутри User или Patient
if (object->isValid()) {
// если валиден то мы можем попробовать его записать в базу
// проверяем новый ли этот объект, т.е. есть ли у него ID из базы данных
if (object->isNewRecord()) {
//реализацию смотри в main.cpp, и у User и у Patient хранилищь будет этот метод немного разный
return _insertRecord(object); //если объект новый то делаем записать в базу, SQL: INSERT INTO ...
}
else {
//реализацию смотри в main.cpp, и у User и у Patient хранилищь будет этот метод немного разный
return _updateRecord(object); //если есть ID - то существующий и просто обновляем его в базе по его ID: UPDATE ...
}
}
return false;
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment