From 385805414e6f3fe46a04ec073caefd61f54e9eb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=98=D0=BB=D1=8C=D1=8F?= <Илья@WIN-RANNDDD> Date: Mon, 20 Jan 2025 19:44:05 +0400 Subject: [PATCH] Moved the implementation of filters, sorting, searching to the DBMS --- HardwareAccountingServer.pro | 5 - data/requestDeviceModels.sql | 10 -- data/requestDevices.sql | 14 -- data/updateDevice.sql | 12 -- service/businesslogic/devicelogic.cpp | 129 ++----------- service/businesslogic/devicelogic.h | 6 - service/serviceloaddb.cpp | 249 +++++++++++++++++++------- service/serviceloaddb.h | 15 +- 8 files changed, 206 insertions(+), 234 deletions(-) delete mode 100644 data/requestDeviceModels.sql delete mode 100644 data/requestDevices.sql delete mode 100644 data/updateDevice.sql diff --git a/HardwareAccountingServer.pro b/HardwareAccountingServer.pro index b66b39d..dfafef7 100644 --- a/HardwareAccountingServer.pro +++ b/HardwareAccountingServer.pro @@ -33,11 +33,6 @@ qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target -DISTFILES += \ - data/requestDeviceModels.sql \ - data/requestDevices.sql \ - data/updateDevice.sql - HEADERS += \ apiserver.h \ models/baseentity.h \ diff --git a/data/requestDeviceModels.sql b/data/requestDeviceModels.sql deleted file mode 100644 index ae5c57f..0000000 --- a/data/requestDeviceModels.sql +++ /dev/null @@ -1,10 +0,0 @@ -SELECT - dm.*, - dt.name AS device_type_name, - m.name AS manufacturer_name -FROM - device_model dm -JOIN - device_type dt ON dm.fk_id_type = dt.id -JOIN - manufacturer m ON dm.fk_id_manuf = m.id; diff --git a/data/requestDevices.sql b/data/requestDevices.sql deleted file mode 100644 index fe106c2..0000000 --- a/data/requestDevices.sql +++ /dev/null @@ -1,14 +0,0 @@ -SELECT - d.*, - l.name AS location_name, - TRIM(CONCAT(e.last_name, ' ', e.first_name, ' ', e.patronymic)) AS employee_full_name, - e.fk_id_department AS department_id, - dep.name AS department_name -FROM - device d -JOIN - location l ON d.fk_id_location = l.id -LEFT JOIN - employee e ON d.fk_id_employee = e.id -LEFT JOIN - department dep ON e.fk_id_department = dep.id; diff --git a/data/updateDevice.sql b/data/updateDevice.sql deleted file mode 100644 index 3b88b7a..0000000 --- a/data/updateDevice.sql +++ /dev/null @@ -1,12 +0,0 @@ -UPDATE device -SET serial_number = '%1', - purchase_date = '%2', - price = '%3', - warranty_expire_date = '%4', - is_working = '%5', - further_information = '%6', - fk_id_location = '%7', - fk_id_employee = '%8', - fk_id_model = '%9', - is_liked = '%10' -WHERE id = '%11'; diff --git a/service/businesslogic/devicelogic.cpp b/service/businesslogic/devicelogic.cpp index ccc70c7..73cb446 100644 --- a/service/businesslogic/devicelogic.cpp +++ b/service/businesslogic/devicelogic.cpp @@ -7,8 +7,15 @@ DeviceLogic::DeviceLogic(ServiceLoadDB *serviceDB) QMap DeviceLogic::getAll() { - _db->loadDeviceModels(); - return _db->loadDevices(); + QMap devicesMap; + + auto devices =_db->loadDevices(-1, EntityType::All, "", FilterParams(), ""); + + for (const Device &device : devices) { + devicesMap.insert(device.id(), device); + } + + return devicesMap; } QList DeviceLogic::getAllByParameters( @@ -18,12 +25,7 @@ QList DeviceLogic::getAllByParameters( const QString &sortOrder ) { - _db->loadDeviceModels(); - auto devices = _db->loadDevices(); - auto filteredDevices = filterByEntity(devices, entityId, entityType); - filteredDevices = searchDevices(filteredDevices, searchText); - filteredDevices = applyFilters(filteredDevices, filterParams); - return sortDevices(filteredDevices, sortOrder); + return _db->loadDevices(entityId, entityType, searchText, filterParams, sortOrder); } bool DeviceLogic::updateDevice(const Device &device) @@ -42,114 +44,3 @@ bool DeviceLogic::updateDevice(const Device &device) } return _db->updateDevice(device); } - -QMap DeviceLogic::filterByEntity(const QMap &devices, int entityId, EntityType entityType) -{ - QMap result; - if (entityId == -1 || entityType == EntityType::All) - return devices; - - for (auto &device : devices) { - switch (entityType) { - case EntityType::DeviceTypes: - if (device.deviceModel().idType() == entityId) - result.insert(device.id(), device); - break; - case EntityType::Locations: - if (device.idLocation() == entityId) - result.insert(device.id(), device); - break; - case EntityType::Departments: - if (device.idDepartment() == entityId) - result.insert(device.id(), device); - break; - case EntityType::Manufacturers: - if (device.deviceModel().idManuf() == entityId) - result.insert(device.id(), device); - break; - case EntityType::DeviceModels: - if (device.deviceModel().id() == entityId) - result.insert(device.id(), device); - break; - default: break; - } - } - return result; -} - -QMap DeviceLogic::searchDevices(const QMap &devices, const QString &searchText) -{ - if (searchText.isEmpty()) - return devices; - - QMap result; - for (auto &device : devices) { - if (device.deviceModel().name().contains(searchText, Qt::CaseInsensitive) || - device.deviceModel().nameType().contains(searchText, Qt::CaseInsensitive) || - device.serialNumber().contains(searchText, Qt::CaseInsensitive)) { - result.insert(device.id(), device); - } - } - return result; -} - -QMap DeviceLogic::applyFilters(const QMap &devices, const FilterParams &filterParams) -{ - if (!filterParams.apllyFilters()) - return devices; - - QMap result; - if (filterParams.disregardState()) - { - for (auto &device : devices) { - if (device.price() < filterParams.priceFrom() || device.price() > filterParams.priceTo()) - continue; - result.insert(device.id(), device); - } - } - else - { - for (auto &device : devices) { - if (device.isWorking() != filterParams.isWorking()) - continue; - if (device.price() < filterParams.priceFrom() || device.price() > filterParams.priceTo()) - continue; - result.insert(device.id(), device); - } - } - - return result; -} - -QList DeviceLogic::sortDevices(QMap &devices, const QString &sortOrder) -{ - QList deviceList = devices.values(); - - if (sortOrder == "Сначала новые") { - std::sort(deviceList.begin(), deviceList.end(), [](const Device &a, const Device &b) { - return a.purchaseDate() > b.purchaseDate(); - }); - } - if (sortOrder == "Сначала старые") { - std::sort(deviceList.begin(), deviceList.end(), [](const Device &a, const Device &b) { - return a.purchaseDate() < b.purchaseDate(); - }); - } - if (sortOrder == "Сначала дешевые") { - std::sort(deviceList.begin(), deviceList.end(), [](const Device &a, const Device &b) { - return a.price() < b.price(); - }); - } - if (sortOrder == "Сначала дорогие") { - std::sort(deviceList.begin(), deviceList.end(), [](const Device &a, const Device &b) { - return a.price() > b.price(); - }); - } - if (sortOrder == "Сначала с лайком") { - std::sort(deviceList.begin(), deviceList.end(), [](const Device &a, const Device &b) { - return a.isLiked() > b.isLiked(); - }); - } - - return deviceList; -} diff --git a/service/businesslogic/devicelogic.h b/service/businesslogic/devicelogic.h index e66a071..5207879 100644 --- a/service/businesslogic/devicelogic.h +++ b/service/businesslogic/devicelogic.h @@ -19,12 +19,6 @@ public: ); bool updateDevice(const Device &device); -private: - QMap filterByEntity(const QMap &devices, int entityId, EntityType entityType); - QMap searchDevices(const QMap &devices, const QString &searchText); - QMap applyFilters(const QMap &devices, const FilterParams &filterParams); - QList sortDevices(QMap &devices, const QString &sortOrder); - private: ServiceLoadDB *_db; }; diff --git a/service/serviceloaddb.cpp b/service/serviceloaddb.cpp index cbd1152..def345a 100644 --- a/service/serviceloaddb.cpp +++ b/service/serviceloaddb.cpp @@ -114,62 +114,158 @@ QMap ServiceLoadDB::loadDeviceTypes() } QMap ServiceLoadDB::loadDeviceModels() -{ - QFile file("../../data/requestDeviceModels.sql"); - if (!file.open(QIODevice::ReadOnly)) { - qDebug() << "Не получилось открыть файл \"requestDeviceModels.sql\""; - return QMap(); - } +{ + QMap mapDeviceModels; - _dbInput = QString(file.readAll()); + _dbInput = "SELECT " + "dm.*, " + "dt.name AS device_type_name, " + "m.name AS manufacturer_name " + "FROM device_model dm " + "JOIN device_type dt ON dm.fk_id_type = dt.id " + "JOIN manufacturer m ON dm.fk_id_manuf = m.id "; if (!_query.exec(_dbInput)) { qDebug() << "Ошибка запроса при получении информации о моделях устройств: " << _query.lastError().text(); - return QMap(); + return mapDeviceModels; } QSqlRecord rec; while (_query.next()) { rec = _query.record(); - DeviceModel deviceModel; - int id = _query.value(rec.indexOf("id")).toInt(); - deviceModel.setId(id); - deviceModel.setName(_query.value(rec.indexOf("name")).toString()); - deviceModel.setDescription(getValueOrDefault(_query, rec, "description", QString("Описание отсутствует"))); - deviceModel.setWorkEfficiency(_query.value(rec.indexOf("work_efficiency")).toInt()); - deviceModel.setReliability(_query.value(rec.indexOf("reliability")).toInt()); - deviceModel.setEnergyEfficiency(_query.value(rec.indexOf("energy_efficiency")).toInt()); - deviceModel.setUserFriendliness(_query.value(rec.indexOf("user_friendliness")).toInt()); - deviceModel.setDurability(_query.value(rec.indexOf("durability")).toInt()); - deviceModel.setAestheticQualities(_query.value(rec.indexOf("aesthetic_qualities")).toInt()); - deviceModel.setIdType(_query.value(rec.indexOf("fk_id_type")).toInt()); - deviceModel.setNameType(_query.value(rec.indexOf("device_type_name")).toString()); - deviceModel.setIdManuf(_query.value(rec.indexOf("fk_id_manuf")).toInt()); - deviceModel.setNameManuf(_query.value(rec.indexOf("manufacturer_name")).toString()); - deviceModel.setStructureElements(readStructureElements(id)); + DeviceModel deviceModel = getModelObject(_query.value(rec.indexOf("id")).toInt(), _query.value(rec.indexOf("name")).toString(), + getValueOrDefault(_query, rec, "description", QString("Описание отсутствует")), _query.value(rec.indexOf("work_efficiency")).toInt(), + _query.value(rec.indexOf("reliability")).toInt(), _query.value(rec.indexOf("energy_efficiency")).toInt(), _query.value(rec.indexOf("user_friendliness")).toInt(), + _query.value(rec.indexOf("durability")).toInt(), _query.value(rec.indexOf("aesthetic_qualities")).toInt(), _query.value(rec.indexOf("fk_id_type")).toInt(), + _query.value(rec.indexOf("device_type_name")).toString(), _query.value(rec.indexOf("fk_id_manuf")).toInt(), _query.value(rec.indexOf("manufacturer_name")).toString()); - _mapDeviceModels.insert(deviceModel.id(), deviceModel); + mapDeviceModels.insert(deviceModel.id(), deviceModel); } - return _mapDeviceModels; + return mapDeviceModels; } -QMap ServiceLoadDB::loadDevices() +QList ServiceLoadDB::loadDevices(int entityId, EntityType entityType, + QString searchText, + const FilterParams &filterParams, + const QString &sortOrder) { - QMap mapDevices; + QList devices; - QFile file("../../data/requestDevices.sql"); - if (!file.open(QIODevice::ReadOnly)) { - qDebug() << "Не получилось открыть файл \"requestDevices.sql\""; - return mapDevices; + QString baseQuery = "SELECT " + "d.*, " + "l.name AS location_name, " + "TRIM(CONCAT(e.last_name, ' ', e.first_name, ' ', e.patronymic)) AS employee_full_name, " + "e.fk_id_department AS department_id, " + "dep.name AS department_name, " + "dm.name AS model_name, " + "dm.description AS model_description, " + "dm.work_efficiency, dm.reliability, dm.energy_efficiency, " + "dm.user_friendliness, dm.durability, dm.aesthetic_qualities, " + "dm.fk_id_type AS device_type_id, " + "dt.name AS device_type_name, " + "dm.fk_id_manuf AS manufacturer_id, " + "m.name AS manufacturer_name " + "FROM device d " + "JOIN device_model dm ON d.fk_id_model = dm.id " + "JOIN manufacturer m ON dm.fk_id_manuf = m.id " + "JOIN device_type dt ON dm.fk_id_type = dt.id " + "JOIN location l ON d.fk_id_location = l.id " + "LEFT JOIN employee e ON d.fk_id_employee = e.id " + "LEFT JOIN department dep ON e.fk_id_department = dep.id "; + + QStringList conditions; + QList params; + + if (entityId != -1 && entityType != EntityType::All) { + switch (entityType) { + case EntityType::DeviceTypes: + conditions.append("d.fk_id_model IN (SELECT id FROM device_model WHERE fk_id_type = ?)"); + params.append(entityId); + break; + case EntityType::Locations: + conditions.append("d.fk_id_location = ?"); + params.append(entityId); + break; + case EntityType::Departments: + conditions.append("d.fk_id_employee IN (SELECT id FROM employee WHERE fk_id_department = ?)"); + params.append(entityId); + break; + case EntityType::Manufacturers: + conditions.append("d.fk_id_model IN (SELECT id FROM device_model WHERE fk_id_manuf = ?)"); + params.append(entityId); + break; + case EntityType::DeviceModels: + conditions.append("d.fk_id_model = ?"); + params.append(entityId); + break; + default: break; + } } - _dbInput = QString(file.readAll()); + if (!searchText.isEmpty()) { + conditions.append("(d.serial_number ILIKE ? OR " + "d.fk_id_model IN (SELECT id FROM device_model WHERE name ILIKE ?) OR " + "d.fk_id_model IN (" + "SELECT dm.id " + "FROM device_model dm " + "JOIN device_type dt ON dm.fk_id_type = dt.id " + "WHERE dt.name ILIKE ?))"); + params.append("%" + searchText + "%"); + params.append("%" + searchText + "%"); + params.append("%" + searchText + "%"); + } - if (!_query.exec(_dbInput)) { + if (filterParams.apllyFilters()) { + if (filterParams.disregardState()) { + conditions.append("d.price BETWEEN ? AND ?"); + params.append(filterParams.priceFrom()); + params.append(filterParams.priceTo()); + } else { + conditions.append("d.is_working = ? AND d.price BETWEEN ? AND ?"); + params.append(filterParams.isWorking()); + params.append(filterParams.priceFrom()); + params.append(filterParams.priceTo()); + } + } + + if (!conditions.isEmpty()) { + baseQuery.append("WHERE " + conditions.join(" AND ")); + } + + if (!sortOrder.isEmpty()) { + if (sortOrder == "Сначала новые") { + baseQuery.append(" ORDER BY d.purchase_date DESC"); + } + if (sortOrder == "Сначала старые") { + baseQuery.append(" ORDER BY d.purchase_date ASC"); + } + if (sortOrder == "Сначала дешевые") { + baseQuery.append(" ORDER BY d.price ASC"); + } + if (sortOrder == "Сначала дорогие") { + baseQuery.append(" ORDER BY d.price DESC"); + } + if (sortOrder == "Сначала с лайком") { + baseQuery.append(" ORDER BY d.is_liked DESC"); + } + } + + _dbInput = baseQuery; + + if (!_query.prepare(_dbInput)) { + qDebug() << "Ошибка подготовки запроса: " << _query.lastError().text(); + return devices; + } + + for (int i = 0; i < params.size(); i++) { + _query.bindValue(i, params[i]); + } + + if (!_query.exec()) { qDebug() << "Ошибка запроса при получении информации о устройствах: " << _query.lastError().text(); - return mapDevices; + return devices; } QSqlRecord rec; @@ -177,14 +273,8 @@ QMap ServiceLoadDB::loadDevices() rec = _query.record(); Device device; - int id = _query.value(rec.indexOf("id")).toInt(); - int idModel = _query.value(rec.indexOf("fk_id_model")).toInt(); - if (!_mapDeviceModels.contains(idModel)) { - qDebug() << "Не загружена модель устройства. Идентификатор устройства: " << id; - return QMap(); - } - device.setId(id); + device.setId(_query.value(rec.indexOf("id")).toInt()); device.setSerialNumber(_query.value(rec.indexOf("serial_number")).toString()); device.setPurchaseDate(_query.value(rec.indexOf("purchase_date")).toDateTime()); device.setPrice(_query.value(rec.indexOf("price")).toDouble()); @@ -197,38 +287,48 @@ QMap ServiceLoadDB::loadDevices() device.setNameEmployee(getValueOrDefault(_query, rec, "employee_full_name", QString("Не назначен"))); device.setIdDepartment(getValueOrDefault(_query, rec, "department_id", 0)); device.setNameDepartment(getValueOrDefault(_query, rec, "department_name", QString("Не относится к отделу"))); - device.setDeviceModel(_mapDeviceModels[idModel]); device.setIsLiked(_query.value(rec.indexOf("is_liked")).toBool()); + device.setDeviceModel(getModelObject(_query.value(rec.indexOf("fk_id_model")).toInt(), _query.value(rec.indexOf("model_name")).toString(), + getValueOrDefault(_query, rec, "model_description", QString("Описание отсутствует")), _query.value(rec.indexOf("work_efficiency")).toInt(), + _query.value(rec.indexOf("reliability")).toInt(), _query.value(rec.indexOf("energy_efficiency")).toInt(), _query.value(rec.indexOf("user_friendliness")).toInt(), + _query.value(rec.indexOf("durability")).toInt(), _query.value(rec.indexOf("aesthetic_qualities")).toInt(), _query.value(rec.indexOf("device_type_id")).toInt(), + _query.value(rec.indexOf("device_type_name")).toString(), _query.value(rec.indexOf("manufacturer_id")).toInt(), _query.value(rec.indexOf("manufacturer_name")).toString())); - mapDevices.insert(device.id(), device); + devices.append(device); } - return mapDevices; + return devices; } bool ServiceLoadDB::updateDevice(const Device &device) { - QFile file("../../data/updateDevice.sql"); - if (!file.open(QIODevice::ReadOnly)) { - qDebug() << "Не удалось открыть файл с запросом для обновления устройства"; - return false; - } + _dbInput = "UPDATE device " + "SET serial_number = ?, " + "purchase_date = ?, " + "price = ?, " + "warranty_expire_date = ?, " + "is_working = ?, " + "further_information = ?, " + "fk_id_location = ?, " + "fk_id_employee = ?, " + "fk_id_model = ?, " + "is_liked = ? " + "WHERE id = ?"; - QString db_input = QString(file.readAll()); + _query.prepare(_dbInput); + _query.bindValue(0, device.serialNumber()); + _query.bindValue(1, device.purchaseDate().toString("yyyy-MM-dd HH:mm:ss")); + _query.bindValue(2, device.price()); + _query.bindValue(3, device.warrantyExpireDate().toString("yyyy-MM-dd HH:mm:ss")); + _query.bindValue(4, device.isWorking() ? "TRUE" : "FALSE"); + _query.bindValue(5, device.furtherInformation()); + _query.bindValue(6, device.idLocation()); + _query.bindValue(7, device.idEmployee()); + _query.bindValue(8, device.deviceModel().id()); + _query.bindValue(9, device.isLiked() ? "TRUE" : "FALSE"); + _query.bindValue(10, device.id()); - db_input = db_input.arg(device.serialNumber()) - .arg(device.purchaseDate().toString("yyyy-MM-dd HH:mm:ss")) - .arg(device.price()) - .arg(device.warrantyExpireDate().toString("yyyy-MM-dd HH:mm:ss")) - .arg(device.isWorking() ? "TRUE" : "FALSE") - .arg(device.furtherInformation()) - .arg(device.idLocation()) - .arg(device.idEmployee()) - .arg(device.deviceModel().id()) - .arg(device.isLiked() ? "TRUE" : "FALSE") - .arg(device.id()); - - if (!_query.exec(db_input)) { + if (!_query.exec()) { qDebug() << "Ошибка обновления устройства с id = " << device.id() << ": " << _query.lastError().text(); return false; } @@ -266,6 +366,27 @@ QList ServiceLoadDB::readStructureElements(int modelId) return elements; } +DeviceModel ServiceLoadDB::getModelObject(int id, QString name, QString description, int workEfficiency, int reliability, int energyEfficiency, int userFriendlines, int durability, + int aestheticQualities, int idType, QString nameType, int idManuf, QString nameManuf) +{ + DeviceModel deviceModel; + deviceModel.setId(id); + deviceModel.setName(name); + deviceModel.setDescription(description); + deviceModel.setWorkEfficiency(workEfficiency); + deviceModel.setReliability(reliability); + deviceModel.setEnergyEfficiency(energyEfficiency); + deviceModel.setUserFriendliness(userFriendlines); + deviceModel.setDurability(durability); + deviceModel.setAestheticQualities(aestheticQualities); + deviceModel.setIdType(idType); + deviceModel.setNameType(nameType); + deviceModel.setIdManuf(idManuf); + deviceModel.setNameManuf(nameManuf); + deviceModel.setStructureElements(readStructureElements(id)); + return deviceModel; +} + template T ServiceLoadDB::getValueOrDefault(const QSqlQuery &query, const QSqlRecord &record, const QString &fieldName, const T &defaultValue) { diff --git a/service/serviceloaddb.h b/service/serviceloaddb.h index f1ca7aa..d674ed9 100644 --- a/service/serviceloaddb.h +++ b/service/serviceloaddb.h @@ -14,6 +14,8 @@ #include #include +#include "models/filterparams.h" +#include "models/enums/entitytype.h" #include "models/types.h" // IWYU pragma: keep class ServiceLoadDB : public QObject @@ -28,21 +30,26 @@ public: QMap loadManufacturers(); QMap loadDeviceTypes(); QMap loadDeviceModels(); - QMap loadDevices(); + QList loadDevices(int entityId, EntityType entityType, + QString searchText, + const FilterParams &filterParams, + const QString &sortOrder); bool updateDevice(const Device &device); private: QList readStructureElements(int modelId); + DeviceModel getModelObject(int id, QString name, QString description, int workEfficiency, int reliability, int energyEfficiency, int userFriendlines, int durability, + int aestheticQualities, int idType, QString nameType, int idManuf, QString nameManuf); template T getValueOrDefault(const QSqlQuery &query, const QSqlRecord &record, const QString &fieldName, const T &defaultValue); private: QSqlDatabase _db; - QString _dbInput; - QSqlQuery _query; - QMap _mapDeviceModels; + QString _dbInput; + + QSqlQuery _query; }; #endif // SERVICELOADDB_H