diff --git a/packages/v1/administrativo/services/log/log_show_database_service.py b/packages/v1/administrativo/services/log/log_show_database_service.py index ac12ab0..cd91345 100644 --- a/packages/v1/administrativo/services/log/log_show_database_service.py +++ b/packages/v1/administrativo/services/log/log_show_database_service.py @@ -71,8 +71,7 @@ def compare_fields(standard_fields: List[Dict], client_fields: List[Dict], table def compare_structures(standard_structure: Dict[str, Any], client_structure: Dict[str, Any]) -> Dict[str, Any]: pass -# --- FUNÇÃO: ELEMENTOS SOMENTE NO PADRÃO (Padrão - Cliente) --- -# Esta função é essencial e deve ser mantida. +# --- NOVO: FUNÇÃO: ELEMENTOS SOMENTE NO PADRÃO (Padrão - Cliente) --- def find_standard_only_elements(standard_structure: Dict[str, Any], client_structure: Dict[str, Any]) -> Dict[str, Any]: """ @@ -149,8 +148,8 @@ def find_standard_only_elements(standard_structure: Dict[str, Any], client_struc return standard_only -# --- FUNÇÃO: ELEMENTOS SOMENTE NO CLIENTE (Removida a necessidade de chamada no execute) --- -# A função é mantida, mas não é chamada, pois não faz parte do retorno desejado. +# --- FUNÇÃO: ELEMENTOS SOMENTE NO CLIENTE (Agora usa chaves UPPERCASE) --- + def find_client_only_elements(standard_structure: Dict[str, Any], client_structure: Dict[str, Any]) -> Dict[str, Any]: """ Identifica elementos presentes na estrutura do cliente mas ausentes na estrutura padrão. @@ -158,26 +157,31 @@ def find_client_only_elements(standard_structure: Dict[str, Any], client_structu """ client_only = {} - # ... (lógica interna da função original) ... - # O conteúdo desta função não precisa ser alterado se não for usado. - # --- 1. TABLES (Lidando com a estrutura achatada do cliente) --- + + # 1a. Normalize e Filtra Tabelas Padrão standard_tables_names = {t.get('TABLE_NAME') for t in standard_structure.get('TABLES', []) if t.get('TABLE_NAME') and not is_ignored(t.get('TABLE_NAME'))} + # 1b. Agrupa e Filtra Campos do Cliente por Nome de Tabela client_fields_by_table: Dict[str, List[Dict]] = {} + # A chave do nível superior agora é 'TABLES' (em UPPERCASE) for field_item in client_structure.get('TABLES', []): table_name = field_item.get('TABLE_NAME') + # Filtra a tabela e o elemento, se for CONVERSAO if table_name and not is_ignored(table_name): if table_name not in client_fields_by_table: client_fields_by_table[table_name] = [] client_fields_by_table[table_name].append(field_item) + # 1c. Encontra Tabelas Exclusivas do Cliente client_tables_names = set(client_fields_by_table.keys()) + unique_table_names = client_tables_names - standard_tables_names client_only_tables = [] for table_name in unique_table_names: + # Retorna a lista de campos agrupados sob o nome da tabela (limpa) client_only_tables.append({ "TABLE_NAME": table_name, "FIELDS": [_remove_source_code(f) for f in client_fields_by_table[table_name]] @@ -187,27 +191,35 @@ def find_client_only_elements(standard_structure: Dict[str, Any], client_structu client_only["TABELAS_UNICAS"] = client_only_tables # --- 2. OUTROS ELEMENTOS (PKs, FKs, etc.) --- + + # Chaves de nível superior agora em UPPERCASE elements_to_check = ['PRIMARY_KEYS', 'FOREIGN_KEYS', 'INDEXES', 'VIEWS', 'PROCEDURES', 'TRIGGERS'] for element_key in elements_to_check: standard_elements = standard_structure.get(element_key, []) client_elements = client_structure.get(element_key, []) + # Cria Sets baseados na representação JSON normalizada (limpa), filtrando IGNORED + + # Standard Set (Filtrado para IGNORED) standard_elements_filtered = [item for item in standard_elements if not is_ignored(get_element_identifier(item))] + # O _remove_source_code é chamado após a normalização. standard_set = {json.dumps(_remove_source_code(item), sort_keys=True) for item in standard_elements_filtered} + # Client Set (Filtrado para IGNORED) client_set_normalized = {} for item in client_elements: identifier = get_element_identifier(item) - if identifier and not is_ignored(identifier): + if identifier and not is_ignored(identifier): # Filtra CONVERSAO cleaned_item = _remove_source_code(item) json_str = json.dumps(cleaned_item, sort_keys=True) client_set_normalized[json_str] = cleaned_item client_set = set(client_set_normalized.keys()) + # Calcula a diferença Cliente - Padrão unique_client_elements_str = client_set - standard_set if unique_client_elements_str: @@ -218,11 +230,10 @@ def find_client_only_elements(standard_structure: Dict[str, Any], client_structu return client_only -# --- CLASSE PRINCIPAL DE SERVIÇO (Modificada) --- +# --- CLASSE PRINCIPAL DE SERVIÇO --- class ShowDatabaseService: - # Esta função helper não é mais estritamente necessária, mas é mantida por segurança/modularidade def _clean_full_structure_for_output(self, structure: Dict[str, Any]) -> Dict[str, Any]: """Cria uma cópia limpa da estrutura, removendo 'SOURCE_CODE' em todos os elementos relevantes. Assume que a estrutura já está em UPPERCASE.""" @@ -232,8 +243,10 @@ class ShowDatabaseService: for key in keys_to_clean: if key in cleaned and isinstance(cleaned[key], list): + # Aplica a limpeza a cada item da lista cleaned[key] = [_remove_source_code(item) for item in cleaned[key]] + # Garante que, se houver campos (FIELDS) aninhados, eles também sejam limpos if 'TABLES' in cleaned and isinstance(cleaned['TABLES'], list): for table in cleaned['TABLES']: if 'FIELDS' in table and isinstance(table['FIELDS'], list): @@ -252,7 +265,7 @@ class ShowDatabaseService: # Extrai e carrega os dados JSON do campo 'file' dados_json = json.loads(dados_json["file"]) - # --- 1. Extração e Carregamento (Standard) --- + # Extrai as estruturas de dados relevantes standard_structure_json_string = dados_json.get("standard_structure_json") standard_structure_data: Dict[str, Any] = {} if standard_structure_json_string: @@ -261,33 +274,57 @@ class ShowDatabaseService: except json.JSONDecodeError: pass - # --- 2. Extração e Carregamento (Client e Metadata) --- + # Extrai a estrutura do cliente do JSON database_data = dados_json.get("database", {}) client_structure: Dict[str, Any] = database_data.get("structure", {}) - partition_info = database_data.get("partition", {}) - - # --- 3. Normalização CRUCIAL --- + + # NOVO PASSO CRUCIAL: Normaliza as chaves para UPPERCASE em ambas as estruturas standard_structure_data = _normalize_keys_to_upper(standard_structure_data) client_structure = _normalize_keys_to_upper(client_structure) + + # Limpa ambas as estruturas de 'source_code' para o output de debug + debug_cliente = self._clean_full_structure_for_output(client_structure) + debug_padrao = self._clean_full_structure_for_output(standard_structure_data) - # --- 4. Comparação FOCADA (Padrão - Cliente) --- - # SOMENTE a função que encontra elementos que faltam no cliente é chamada. + # Encontra elementos exclusivos do cliente (Cliente - Padrão) + elementos_unicos_cliente = find_client_only_elements( + standard_structure_data, + client_structure + ) + + # NOVO: Encontra elementos exclusivos do padrão (Padrão - Cliente) elementos_unicos_padrao = find_standard_only_elements( standard_structure_data, client_structure ) + + # Separa o campo 'partition' das demais chaves + partition_info = database_data.get("partition", {}) + + # Separa o campo file_size_mb das demais chaves + file_size_mb = database_data.get("file_size_mb", None) + + # Separa o campo db_accessible das demais chaves + db_accessible = database_data.get("db_accessible", None) + + # Separa o campo db_accessible das demais chaves + last_modified = database_data.get("last_modified", None) - # --- 5. Monta o JSON final SIMPLIFICADO --- + # Monta o JSON final data = { - # Mantém a metadata básica "cns": dados_json.get("cns"), "cartorio": dados_json.get("cartorio"), "data": dados_json.get("data"), "hora": dados_json.get("hora"), "database": { "partition": partition_info, - # Remove default_schema, client_schema e client_only_items - "standard_only_items": elementos_unicos_padrao + # "default_schema": debug_padrao, + # "client_schema": debug_cliente, + # "client_only_items": elementos_unicos_cliente, + # "standard_only_items": elementos_unicos_padrao, + "file_size_mb": file_size_mb, + "db_accessible": db_accessible, + "last_modified": last_modified } }