-
-
Save elja/baedecdae971514c4053abd78424c461 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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