From 21d079f28587cc3d2c902fb684b139c3a93ea5ae Mon Sep 17 00:00:00 2001 From: Your Name Date: Sun, 25 May 2025 12:57:13 +1200 Subject: [PATCH] Bug fixing --- src/database.cpp | 122 +++++++++++++++++++---------------------------- src/database.hpp | 3 +- 2 files changed, 50 insertions(+), 75 deletions(-) diff --git a/src/database.cpp b/src/database.cpp index 81af263..c57c9e4 100644 --- a/src/database.cpp +++ b/src/database.cpp @@ -11,8 +11,7 @@ bool Database::createObjectsTable() { const char* create_table_sql = "CREATE TABLE IF NOT EXISTS objects (" "hash TEXT PRIMARY KEY," - "labels TEXT NOT NULL," // JSON array of labels - "tags TEXT NOT NULL," // JSON array of tags + "label_tags TEXT NOT NULL," // JSON array of label:tag pairs "metadata TEXT NOT NULL" ");"; @@ -187,10 +186,10 @@ bool Database::get(const std::string& key, dbEntry& entry) { std::string sql; if (key.find(':') != std::string::npos) { // Query by label:tag - sql = "SELECT hash, labels, tags, metadata FROM objects WHERE labels LIKE ? AND tags LIKE ?;"; + sql = "SELECT hash, label_tags, metadata FROM objects WHERE label_tags LIKE ?;"; } else { // Query by hash - sql = "SELECT hash, labels, tags, metadata FROM objects WHERE hash = ?;"; + sql = "SELECT hash, label_tags, metadata FROM objects WHERE hash = ?;"; } sqlite3_stmt* stmt; @@ -199,17 +198,9 @@ bool Database::get(const std::string& key, dbEntry& entry) { } if (key.find(':') != std::string::npos) { - // Split label:tag - size_t pos = key.find(':'); - std::string label = key.substr(0, pos); - std::string tag = key.substr(pos + 1); - - // Create JSON array patterns for LIKE query - std::string label_pattern = "%\"" + label + "\"%"; - std::string tag_pattern = "%\"" + tag + "\"%"; - - sqlite3_bind_text(stmt, 1, label_pattern.c_str(), -1, SQLITE_STATIC); - sqlite3_bind_text(stmt, 2, tag_pattern.c_str(), -1, SQLITE_STATIC); + // Create JSON array pattern for LIKE query + std::string label_tag_pattern = "%\"" + key + "\"%"; + sqlite3_bind_text(stmt, 1, label_tag_pattern.c_str(), -1, SQLITE_STATIC); } else { sqlite3_bind_text(stmt, 1, key.c_str(), -1, SQLITE_STATIC); } @@ -220,12 +211,10 @@ bool Database::get(const std::string& key, dbEntry& entry) { } entry.hash = reinterpret_cast(sqlite3_column_text(stmt, 0)); - std::string labels_str = reinterpret_cast(sqlite3_column_text(stmt, 1)); - std::string tags_str = reinterpret_cast(sqlite3_column_text(stmt, 2)); - std::string metadata_str = reinterpret_cast(sqlite3_column_text(stmt, 3)); + std::string label_tags_str = reinterpret_cast(sqlite3_column_text(stmt, 1)); + std::string metadata_str = reinterpret_cast(sqlite3_column_text(stmt, 2)); - entry.labels = nlohmann::json::parse(labels_str).get>(); - entry.tags = nlohmann::json::parse(tags_str).get>(); + entry.label_tags = nlohmann::json::parse(label_tags_str).get>(); entry.metadata = nlohmann::json::parse(metadata_str); sqlite3_finalize(stmt); @@ -233,7 +222,7 @@ bool Database::get(const std::string& key, dbEntry& entry) { } bool Database::list(std::vector& entries) { - std::string sql = "SELECT hash, labels, tags, metadata FROM objects;"; + std::string sql = "SELECT hash, label_tags, metadata FROM objects;"; sqlite3_stmt* stmt; if (sqlite3_prepare_v2(db_, sql.c_str(), -1, &stmt, nullptr) != SQLITE_OK) { @@ -244,12 +233,10 @@ bool Database::list(std::vector& entries) { while (sqlite3_step(stmt) == SQLITE_ROW) { dbEntry entry; entry.hash = reinterpret_cast(sqlite3_column_text(stmt, 0)); - std::string labels_str = reinterpret_cast(sqlite3_column_text(stmt, 1)); - std::string tags_str = reinterpret_cast(sqlite3_column_text(stmt, 2)); - std::string metadata_str = reinterpret_cast(sqlite3_column_text(stmt, 3)); + std::string label_tags_str = reinterpret_cast(sqlite3_column_text(stmt, 1)); + std::string metadata_str = reinterpret_cast(sqlite3_column_text(stmt, 2)); - entry.labels = nlohmann::json::parse(labels_str).get>(); - entry.tags = nlohmann::json::parse(tags_str).get>(); + entry.label_tags = nlohmann::json::parse(label_tags_str).get>(); entry.metadata = nlohmann::json::parse(metadata_str); entries.push_back(entry); } @@ -259,16 +246,13 @@ bool Database::list(std::vector& entries) { } bool Database::merge_existing_entry(const dbEntry& existing, const dbEntry& new_entry, dbEntry& merged) { - // Merge labels and tags - std::set merged_labels(existing.labels.begin(), existing.labels.end()); - merged_labels.insert(new_entry.labels.begin(), new_entry.labels.end()); - std::set merged_tags(existing.tags.begin(), existing.tags.end()); - merged_tags.insert(new_entry.tags.begin(), new_entry.tags.end()); + // Merge label:tag pairs + std::set merged_label_tags(existing.label_tags.begin(), existing.label_tags.end()); + merged_label_tags.insert(new_entry.label_tags.begin(), new_entry.label_tags.end()); // Create merged entry merged = new_entry; // Start with new entry's data - merged.labels = std::vector(merged_labels.begin(), merged_labels.end()); - merged.tags = std::vector(merged_tags.begin(), merged_tags.end()); + merged.label_tags = std::vector(merged_label_tags.begin(), merged_label_tags.end()); // Update metadata - preserve fields from existing entry that aren't in new entry merged.metadata = existing.metadata; // Start with existing metadata @@ -277,26 +261,23 @@ bool Database::merge_existing_entry(const dbEntry& existing, const dbEntry& new_ } // Ensure required fields are set correctly - merged.metadata["labels"] = merged.labels; - merged.metadata["tags"] = merged.tags; + merged.metadata["label_tags"] = merged.label_tags; merged.metadata["hash"] = merged.hash; // Update database - std::string sql = "UPDATE objects SET labels = ?, tags = ?, metadata = ? WHERE hash = ?;"; + std::string sql = "UPDATE objects SET label_tags = ?, metadata = ? WHERE hash = ?;"; sqlite3_stmt* stmt; if (sqlite3_prepare_v2(db_, sql.c_str(), -1, &stmt, nullptr) != SQLITE_OK) { return false; } - std::string labels_str = nlohmann::json(merged.labels).dump(); - std::string tags_str = nlohmann::json(merged.tags).dump(); + std::string label_tags_str = nlohmann::json(merged.label_tags).dump(); std::string metadata_str = merged.metadata.dump(); - sqlite3_bind_text(stmt, 1, labels_str.c_str(), -1, SQLITE_STATIC); - sqlite3_bind_text(stmt, 2, tags_str.c_str(), -1, SQLITE_STATIC); - sqlite3_bind_text(stmt, 3, metadata_str.c_str(), -1, SQLITE_STATIC); - sqlite3_bind_text(stmt, 4, merged.hash.c_str(), -1, SQLITE_STATIC); + sqlite3_bind_text(stmt, 1, label_tags_str.c_str(), -1, SQLITE_STATIC); + sqlite3_bind_text(stmt, 2, metadata_str.c_str(), -1, SQLITE_STATIC); + sqlite3_bind_text(stmt, 3, merged.hash.c_str(), -1, SQLITE_STATIC); bool success = sqlite3_step(stmt) == SQLITE_DONE; sqlite3_finalize(stmt); @@ -304,27 +285,24 @@ bool Database::merge_existing_entry(const dbEntry& existing, const dbEntry& new_ } bool Database::insert_new_entry(const dbEntry& entry) { - std::string sql = "INSERT INTO objects (hash, labels, tags, metadata) VALUES (?, ?, ?, ?);"; + std::string sql = "INSERT INTO objects (hash, label_tags, metadata) VALUES (?, ?, ?);"; sqlite3_stmt* stmt; if (sqlite3_prepare_v2(db_, sql.c_str(), -1, &stmt, nullptr) != SQLITE_OK) { return false; } - // Update metadata to include labels, tags, and hash + // Update metadata to include label_tags and hash nlohmann::json metadata = entry.metadata; - metadata["labels"] = entry.labels; - metadata["tags"] = entry.tags; + metadata["label_tags"] = entry.label_tags; metadata["hash"] = entry.hash; - std::string labels_str = nlohmann::json(entry.labels).dump(); - std::string tags_str = nlohmann::json(entry.tags).dump(); + std::string label_tags_str = nlohmann::json(entry.label_tags).dump(); std::string metadata_str = metadata.dump(); sqlite3_bind_text(stmt, 1, entry.hash.c_str(), -1, SQLITE_STATIC); - sqlite3_bind_text(stmt, 2, labels_str.c_str(), -1, SQLITE_STATIC); - sqlite3_bind_text(stmt, 3, tags_str.c_str(), -1, SQLITE_STATIC); - sqlite3_bind_text(stmt, 4, metadata_str.c_str(), -1, SQLITE_STATIC); + sqlite3_bind_text(stmt, 2, label_tags_str.c_str(), -1, SQLITE_STATIC); + sqlite3_bind_text(stmt, 3, metadata_str.c_str(), -1, SQLITE_STATIC); bool success = sqlite3_step(stmt) == SQLITE_DONE; sqlite3_finalize(stmt); @@ -332,56 +310,54 @@ bool Database::insert_new_entry(const dbEntry& entry) { } bool Database::handle_tag_conflicts(const dbEntry& entry) { - for (const auto& label : entry.labels) { - // Find all entries with this label - std::string find_sql = "SELECT hash, labels, tags, metadata FROM objects WHERE labels LIKE ?;"; + for (const auto& label_tag : entry.label_tags) { + // Find all entries with this exact label:tag pair + std::string find_sql = "SELECT hash, label_tags, metadata FROM objects WHERE label_tags LIKE ?;"; sqlite3_stmt* stmt; if (sqlite3_prepare_v2(db_, find_sql.c_str(), -1, &stmt, nullptr) != SQLITE_OK) { return false; } - std::string label_pattern = "%\"" + label + "\"%"; - sqlite3_bind_text(stmt, 1, label_pattern.c_str(), -1, SQLITE_STATIC); + std::string label_tag_pattern = "%\"" + label_tag + "\"%"; + sqlite3_bind_text(stmt, 1, label_tag_pattern.c_str(), -1, SQLITE_STATIC); while (sqlite3_step(stmt) == SQLITE_ROW) { std::string other_hash = reinterpret_cast(sqlite3_column_text(stmt, 0)); if (other_hash == entry.hash) continue; // Skip our own entry - std::string other_labels_str = reinterpret_cast(sqlite3_column_text(stmt, 1)); - std::string other_tags_str = reinterpret_cast(sqlite3_column_text(stmt, 2)); - std::string other_metadata_str = reinterpret_cast(sqlite3_column_text(stmt, 3)); + std::string other_label_tags_str = reinterpret_cast(sqlite3_column_text(stmt, 1)); + std::string other_metadata_str = reinterpret_cast(sqlite3_column_text(stmt, 2)); // Parse the other entry dbEntry other; other.hash = other_hash; - other.labels = nlohmann::json::parse(other_labels_str).get>(); - other.tags = nlohmann::json::parse(other_tags_str).get>(); + other.label_tags = nlohmann::json::parse(other_label_tags_str).get>(); other.metadata = nlohmann::json::parse(other_metadata_str); - // Remove any tags that are in our entry - std::vector new_tags; - for (const auto& tag : other.tags) { - if (std::find(entry.tags.begin(), entry.tags.end(), tag) == entry.tags.end()) { - new_tags.push_back(tag); + // Remove the exact label:tag pair + std::vector new_label_tags; + for (const auto& other_label_tag : other.label_tags) { + if (other_label_tag != label_tag) { + new_label_tags.push_back(other_label_tag); } } - // Update the other entry if it had any tags removed - if (new_tags.size() != other.tags.size()) { - other.tags = new_tags; - other.metadata["tags"] = new_tags; // Update metadata to match + // Update the other entry if it had the label:tag pair removed + if (new_label_tags.size() != other.label_tags.size()) { + other.label_tags = new_label_tags; + other.metadata["label_tags"] = new_label_tags; // Update metadata to match - std::string update_sql = "UPDATE objects SET tags = ?, metadata = ? WHERE hash = ?;"; + std::string update_sql = "UPDATE objects SET label_tags = ?, metadata = ? WHERE hash = ?;"; sqlite3_stmt* update_stmt; if (sqlite3_prepare_v2(db_, update_sql.c_str(), -1, &update_stmt, nullptr) != SQLITE_OK) { sqlite3_finalize(stmt); return false; } - std::string new_tags_str = nlohmann::json(new_tags).dump(); + std::string new_label_tags_str = nlohmann::json(new_label_tags).dump(); std::string new_metadata_str = other.metadata.dump(); - sqlite3_bind_text(update_stmt, 1, new_tags_str.c_str(), -1, SQLITE_STATIC); + sqlite3_bind_text(update_stmt, 1, new_label_tags_str.c_str(), -1, SQLITE_STATIC); sqlite3_bind_text(update_stmt, 2, new_metadata_str.c_str(), -1, SQLITE_STATIC); sqlite3_bind_text(update_stmt, 3, other.hash.c_str(), -1, SQLITE_STATIC); diff --git a/src/database.hpp b/src/database.hpp index 2bd34e2..fd5f0ca 100644 --- a/src/database.hpp +++ b/src/database.hpp @@ -12,8 +12,7 @@ namespace simple_object_storage { class dbEntry { public: std::string hash; // unique primary key - std::vector labels; // multiple labels - std::vector tags; // multiple tags + std::vector label_tags; // multiple label:tag pairs nlohmann::json metadata; };