#pragma once #include #include #include #include #include #include // Operaciones CRUD sobre operations.db (entities + relations) y deteccion // heuristica de tipo a partir de texto libre. Pensado para que la toolbar y // el menu contextual del viewport puedan modificar el grafo y luego pedir // reload (issue 0049g flow). // // Convencion edge labels: si el caller no pasa nombre de relacion, se usa // k_default_relation_name = "RELATED_TO". Los enrichers deben pasar siempre // un nombre semantico (ej: "EXTRACTED_FROM", "RESOLVES_TO", ...). namespace ge { constexpr const char* k_default_relation_name = "RELATED_TO"; enum DetectedType { DT_TEXT = 0, DT_EMAIL, DT_IP_ADDRESS, DT_URL, DT_DOMAIN, DT_PHONE, }; DetectedType detect_type(const char* text); const char* detected_type_name(DetectedType dt); // Inserta una entidad nueva. Si type_ref es NULL/vacio se infiere via // detect_type(name). Genera un id unico ("_"). Devuelve el id // en out_id (caller-owned buffer >= 64). Retorna false si SQLite falla. bool entity_insert(const char* db_path, const char* name, const char* type_ref, char* out_id, size_t out_id_n); bool entity_delete(const char* db_path, const char* id); bool entity_update_type(const char* db_path, const char* id, const char* new_type); // Duplica una entidad existente. Mismo type/metadata, sufijo "_copy" en id // y "(copia)" en name. Devuelve el nuevo id en out_id. bool entity_duplicate(const char* db_path, const char* id, char* out_id, size_t out_id_n); // Inserta una relacion. Si name es NULL/vacio usa k_default_relation_name. bool relation_insert(const char* db_path, const char* from_id, const char* to_id, const char* name); // Lee la columna `notes` (markdown) de una entidad. out se reasigna; vacio si // no existe la entidad. bool entity_get_notes(const char* db_path, const char* id, std::string* out); // Sobrescribe `notes` con el contenido proporcionado. Toca `updated_at`. bool entity_set_notes(const char* db_path, const char* id, const char* notes); // ---------------------------------------------------------------------------- // Inspector editable (issue 0008) // ---------------------------------------------------------------------------- // Un campo de la columna `metadata` JSON. `is_string=true` se emite como // "..." en JSON; false se emite como literal (number/bool/null). El parser // rellena esto al leer; el caller puede sobreescribirlo basado en el schema // del tipo antes de guardar. struct MetadataField { std::string key; std::string value_str; bool is_string = true; }; // Snapshot completo de los campos editables de una entidad. No incluye // `notes` (panel separado) ni `created_at` (no editable). struct EntityRecord { std::string id; std::string name; std::string type_ref; std::string description; std::string status; // active|stale|corrupted|archived std::vector tags; std::vector metadata; // orden preservado del JSON original }; // Carga el snapshot editable de la entidad. Devuelve false si no existe o // SQLite falla. Tags y metadata se parsean desde JSON. bool entity_load_full(const char* db_path, const char* id, EntityRecord* out); // Persiste el snapshot. Toca `updated_at`. Tags y metadata se serializan a // JSON. Devuelve false si SQLite falla. bool entity_update(const char* db_path, const EntityRecord& rec); // Lista las tags distintas en uso en toda la BD (para autocomplete del // chip-input del Inspector). Sin orden particular. bool entity_list_distinct_tags(const char* db_path, std::vector* out); // Mapa user_data (FNV1a hash) -> sql id. Se reconstruye despues de cada // carga del grafo (graph_sources usa FNV1a sobre id como user_data). struct EntityIndex { std::unordered_map by_hash; }; // Escanea operations.db y rellena el indice. Reentrante (clear+repoblar). bool entity_index_build(const char* db_path, EntityIndex* idx); // Resuelve user_data a sql id. NULL si no existe. const char* entity_index_lookup(const EntityIndex& idx, uint64_t user_data); } // namespace ge