#include #include #include #include #include using json = nlohmann::json; class SwissDamedConverter { private: sqlite3* db; void executeSQL(const std::string& sql) { char* errMsg = nullptr; int rc = sqlite3_exec(db, sql.c_str(), nullptr, nullptr, &errMsg); if (rc != SQLITE_OK) { std::cerr << "SQL error: " << errMsg << std::endl; sqlite3_free(errMsg); throw std::runtime_error("SQL execution failed"); } } void createTables() { executeSQL(R"( CREATE TABLE IF NOT EXISTS devices ( id TEXT PRIMARY KEY, basic_udi_di_code TEXT, device_type TEXT, applicable_legislation TEXT, model_name TEXT, device_name TEXT, risk_class TEXT, owner TEXT, company_name TEXT, ar_company_name TEXT, last_modified_at TEXT, matches_search_criteria TEXT ); )"); executeSQL(R"( CREATE TABLE IF NOT EXISTS udi_dis ( id TEXT PRIMARY KEY, device_id TEXT, udi_di_code TEXT, base_quantity INTEGER, last_modified_at TEXT, market_status TEXT, matches_search_criteria TEXT, FOREIGN KEY (device_id) REFERENCES devices(id) ); )"); executeSQL(R"( CREATE TABLE IF NOT EXISTS trade_names ( id INTEGER PRIMARY KEY AUTOINCREMENT, udi_di_id TEXT, language TEXT, text_value TEXT, FOREIGN KEY (udi_di_id) REFERENCES udi_dis(id) ); )"); executeSQL(R"( CREATE TABLE IF NOT EXISTS package_udi_dis ( id TEXT PRIMARY KEY, parent_udi_di_id TEXT, parent_package_id TEXT, package_udi_di_code TEXT, number_of_items INTEGER, total_number_of_devices INTEGER, last_modified_at TEXT, market_status TEXT, matches_search_criteria TEXT, FOREIGN KEY (parent_udi_di_id) REFERENCES udi_dis(id), FOREIGN KEY (parent_package_id) REFERENCES package_udi_dis(id) ); )"); } std::string getJsonString(const json& obj, const std::string& key, const std::string& defaultVal = "") { if (obj.contains(key) && !obj[key].is_null()) { return obj[key].get(); } return defaultVal; } void insertDevice(const json& device) { sqlite3_stmt* stmt; const char* sql = R"( INSERT INTO devices VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) )"; sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr); std::string id = getJsonString(device, "id"); std::string basicUdiDiCode = getJsonString(device, "basicUdiDiCode"); std::string deviceType = getJsonString(device, "deviceType"); std::string applicableLegislation = getJsonString(device, "applicableLegislation"); std::string modelName = getJsonString(device, "modelName"); std::string deviceName = getJsonString(device, "deviceName"); std::string riskClass = getJsonString(device, "riskClass"); std::string owner = getJsonString(device, "owner"); std::string companyName = getJsonString(device, "companyName"); std::string arCompanyName = getJsonString(device, "arCompanyName"); std::string lastModifiedAt = getJsonString(device, "lastModifiedAt"); std::string matchesSearchCriteria = getJsonString(device, "matchesSearchCriteria"); sqlite3_bind_text(stmt, 1, id.c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 2, basicUdiDiCode.c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 3, deviceType.c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 4, applicableLegislation.c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 5, modelName.c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 6, deviceName.c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 7, riskClass.c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 8, owner.c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 9, companyName.c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 10, arCompanyName.c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 11, lastModifiedAt.c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 12, matchesSearchCriteria.c_str(), -1, SQLITE_TRANSIENT); if (sqlite3_step(stmt) != SQLITE_DONE) { std::cerr << "Error inserting device: " << sqlite3_errmsg(db) << std::endl; } sqlite3_finalize(stmt); } void insertUdiDi(const json& udiDi, const std::string& deviceId) { sqlite3_stmt* stmt; const char* sql = R"( INSERT INTO udi_dis VALUES (?, ?, ?, ?, ?, ?, ?) )"; sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr); std::string id = getJsonString(udiDi, "id"); std::string udiDiCode = getJsonString(udiDi, "udiDiCode"); int baseQuantity = udiDi.contains("baseQuantity") && !udiDi["baseQuantity"].is_null() ? udiDi["baseQuantity"].get() : 0; std::string lastModifiedAt = getJsonString(udiDi, "lastModifiedAt"); std::string marketStatus = getJsonString(udiDi, "marketStatus"); std::string matchesSearchCriteria = getJsonString(udiDi, "matchesSearchCriteria"); sqlite3_bind_text(stmt, 1, id.c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 2, deviceId.c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 3, udiDiCode.c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_int(stmt, 4, baseQuantity); sqlite3_bind_text(stmt, 5, lastModifiedAt.c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 6, marketStatus.c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 7, matchesSearchCriteria.c_str(), -1, SQLITE_TRANSIENT); sqlite3_step(stmt); sqlite3_finalize(stmt); // Insert trade names if (udiDi.contains("tradeNames") && udiDi["tradeNames"].is_array()) { for (const auto& tradeName : udiDi["tradeNames"]) { insertTradeName(tradeName, id); } } // Insert package UDI-DIs if (udiDi.contains("packageUdiDis") && udiDi["packageUdiDis"].is_array()) { for (const auto& pkg : udiDi["packageUdiDis"]) { insertPackageUdiDi(pkg, id, ""); } } } void insertTradeName(const json& tradeName, const std::string& udiDiId) { sqlite3_stmt* stmt; const char* sql = "INSERT INTO trade_names (udi_di_id, language, text_value) VALUES (?, ?, ?)"; std::string language = getJsonString(tradeName, "language"); std::string textValue = getJsonString(tradeName, "textValue"); sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr); sqlite3_bind_text(stmt, 1, udiDiId.c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 2, language.c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 3, textValue.c_str(), -1, SQLITE_TRANSIENT); sqlite3_step(stmt); sqlite3_finalize(stmt); } void insertPackageUdiDi(const json& pkg, const std::string& udiDiId, const std::string& parentPkgId) { sqlite3_stmt* stmt; const char* sql = R"( INSERT INTO package_udi_dis VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?) )"; sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr); std::string pkgId = getJsonString(pkg, "id"); std::string packageUdiDiCode = getJsonString(pkg, "packageUdiDiCode"); int numberOfItems = pkg.contains("numberOfItems") && !pkg["numberOfItems"].is_null() ? pkg["numberOfItems"].get() : 0; int totalNumberOfDevices = pkg.contains("totalNumberOfDevices") && !pkg["totalNumberOfDevices"].is_null() ? pkg["totalNumberOfDevices"].get() : 0; std::string lastModifiedAt = getJsonString(pkg, "lastModifiedAt"); std::string marketStatus = getJsonString(pkg, "marketStatus"); std::string matchesSearchCriteria = getJsonString(pkg, "matchesSearchCriteria"); sqlite3_bind_text(stmt, 1, pkgId.c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 2, parentPkgId.empty() ? udiDiId.c_str() : nullptr, -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 3, parentPkgId.empty() ? nullptr : parentPkgId.c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 4, packageUdiDiCode.c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_int(stmt, 5, numberOfItems); sqlite3_bind_int(stmt, 6, totalNumberOfDevices); sqlite3_bind_text(stmt, 7, lastModifiedAt.c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 8, marketStatus.c_str(), -1, SQLITE_TRANSIENT); sqlite3_bind_text(stmt, 9, matchesSearchCriteria.c_str(), -1, SQLITE_TRANSIENT); sqlite3_step(stmt); sqlite3_finalize(stmt); // Insert children recursively if (pkg.contains("children") && pkg["children"].is_array()) { for (const auto& child : pkg["children"]) { insertPackageUdiDi(child, udiDiId, pkgId); } } } public: SwissDamedConverter(const std::string& dbPath) { int rc = sqlite3_open(dbPath.c_str(), &db); if (rc) { throw std::runtime_error("Cannot open database: " + std::string(sqlite3_errmsg(db))); } createTables(); } ~SwissDamedConverter() { sqlite3_close(db); } void convertJsonFile(const std::string& jsonPath) { std::ifstream file(jsonPath); if (!file.is_open()) { throw std::runtime_error("Cannot open JSON file"); } json data; file >> data; executeSQL("BEGIN TRANSACTION"); try { for (const auto& device : data["values"]) { insertDevice(device); if (device.contains("udiDis") && device["udiDis"].is_array()) { std::string deviceId = getJsonString(device, "id"); for (const auto& udiDi : device["udiDis"]) { insertUdiDi(udiDi, deviceId); } } } executeSQL("COMMIT"); std::cout << "Successfully converted " << data["values"].size() << " devices to SQLite database" << std::endl; } catch (...) { executeSQL("ROLLBACK"); throw; } } }; int main(int argc, char* argv[]) { if (argc != 3) { std::cerr << "Usage: " << argv[0] << " " << std::endl; return 1; } try { SwissDamedConverter converter(argv[2]); converter.convertJsonFile(argv[1]); } catch (const std::exception& e) { std::cerr << "Error: " << e.what() << std::endl; return 1; } return 0; }