From 78fdb706eb1abe32223b0650bbcd7e3d74a36299 Mon Sep 17 00:00:00 2001 From: Kenio de Souza Date: Sat, 15 Nov 2025 13:13:04 -0300 Subject: [PATCH] =?UTF-8?q?fix():=20Ajuste=20na=20fun=C3=A7=C3=A3o=20que?= =?UTF-8?q?=20efetua=20auditoria=20no=20banco=20de=20dados?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../services/log/log_show_database_service.py | 83 ++++++++++++++----- 1 file changed, 64 insertions(+), 19 deletions(-) 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 e28cb2d..9718e09 100644 --- a/packages/v1/administrativo/services/log/log_show_database_service.py +++ b/packages/v1/administrativo/services/log/log_show_database_service.py @@ -9,20 +9,37 @@ from packages.v1.administrativo.schemas.log_schema import LogClientIdSchema from packages.v1.administrativo.actions.log.log_show_database_action import ShowDatabaseAction -# Função auxiliar para comparação de campos +# --- FUNÇÃO AUXILIAR PARA COMPARAÇÃO DE CAMPOS (Fornecida e Mantida) --- + def compare_fields(standard_fields: List[Dict], client_fields: List[Dict], table_name: str) -> List[Dict]: """ Compara os campos de uma tabela entre as estruturas padrão e cliente. """ discrepancies = [] - # 1. Mapear campos do cliente por nome para fácil lookup - client_fields_map = {field['FIELD_NAME']: field for field in client_fields} + # Mapear campos do cliente por nome para fácil lookup + # Esta linha pode causar KeyError: 'FIELD_NAME' se os dados forem malformados. + # Assumimos que a lista de campos é mais confiável do que a lista de tabelas. + try: + client_fields_map = {field['FIELD_NAME']: field for field in client_fields} + except KeyError as e: + # Se ocorrer um erro aqui, a lista de campos está malformada. + # Reportamos isso como uma discrepância na tabela. + return [{ + "tabela": table_name, + "tipo": "Erro de Estrutura Interna", + "detalhe": f"Um ou mais campos na tabela do cliente não possuem a chave {e}.", + "padrao": None, + "cliente": client_fields + }] # 2. Iterar sobre os campos padrão e verificar se existem no cliente for standard_field in standard_fields: field_name = standard_field.get('FIELD_NAME') + if not field_name: # Verificação de segurança adicional + continue + if field_name not in client_fields_map: # Campo que existe no padrão mas não no cliente discrepancies.append({ @@ -44,8 +61,7 @@ def compare_fields(standard_fields: List[Dict], client_fields: List[Dict], table standard_value = standard_field.get(attr) client_value = client_field.get(attr) - # Nota: A comparação de strings JSON é mais simples, - # mas requer normalização (ex: null vs NULL, aspas, etc.). + # Nota: Normalize strings/tipos, se necessário, antes desta comparação final if standard_value != client_value: discrepancies.append({ "tabela": table_name, @@ -58,16 +74,22 @@ def compare_fields(standard_fields: List[Dict], client_fields: List[Dict], table return discrepancies +# --- FUNÇÃO PRINCIPAL DE COMPARAÇÃO DE ESTRUTURAS (AJUSTADA) --- + def compare_structures(standard_structure: Dict[str, Any], client_structure: Dict[str, Any]) -> Dict[str, Any]: """ Compara a estrutura do cliente com a estrutura padrão e lista as discrepâncias. + + Ajuste aplicado: Mapeamento seguro das tabelas do cliente para evitar KeyError + se algum item na lista 'tables' estiver sem a chave 'TABLE_NAME'. """ audit_log = { "discrepancias_encontradas": False, "detalhes": { "tabelas_faltando": [], - "elementos_faltando": [], # Para PKs, FKs, Views, etc. - "divergencia_de_campos": [] # Para divergências dentro das tabelas + "elementos_faltando": [], + "divergencia_de_campos": [], + "estrutura_malformada_cliente": None # Novo campo para registrar erros de TABLE_NAME } } @@ -76,27 +98,47 @@ def compare_structures(standard_structure: Dict[str, Any], client_structure: Dic audit_log["discrepancias_encontradas"] = True return audit_log - # Mapear tabelas padrão e cliente por nome + # 1.1 Mapear tabelas padrão (Assumindo que o JSON padrão é sempre correto) standard_tables_map = {t['TABLE_NAME']: t for t in standard_structure.get('tables', [])} - client_tables_map = {t['TABLE_NAME']: t for t in client_structure.get('tables', [])} + # 1.2 Mapear tabelas cliente (COM TRATAMENTO DE ERRO: correção para 'KeyError: TABLE_NAME') + client_tables_map = {} + malformed_tables_data = [] + + for t in client_structure.get('tables', []): + table_name = t.get('TABLE_NAME') # Acesso seguro com .get() + + if table_name: + client_tables_map[table_name] = t + else: + # Captura objetos que não têm a chave TABLE_NAME para log + malformed_tables_data.append(t) + + # 1.3 Se houve dados malformados, registre na auditoria + if malformed_tables_data: + audit_log["discrepancias_encontradas"] = True + audit_log["detalhes"]["estrutura_malformada_cliente"] = { + "descricao": "Alguns objetos na lista 'tables' do cliente não possuem a chave 'TABLE_NAME' e foram ignorados.", + "objetos_problematicos": malformed_tables_data + } + # --- 1. AUDITORIA DE TABELAS E SEUS CAMPOS --- - # 1.1 Tabelas Faltando (No padrão, mas não no cliente) + # 1.4 Tabelas Faltando (No padrão, mas não no cliente) missing_tables = standard_tables_map.keys() - client_tables_map.keys() if missing_tables: audit_log["discrepancias_encontradas"] = True audit_log["detalhes"]["tabelas_faltando"].extend(sorted(list(missing_tables))) - # 1.2 Tabelas Correspondentes (Verificação de Campos) + # 1.5 Tabelas Correspondentes (Verificação de Campos) for table_name, standard_table in standard_tables_map.items(): if table_name in client_tables_map: client_table = client_tables_map[table_name] - # Assume que os campos são listados sob a chave 'FIELDS' standard_fields = standard_table.get('FIELDS', []) client_fields = client_table.get('FIELDS', []) + # Chama a função compare_fields field_discrepancies = compare_fields(standard_fields, client_fields, table_name) if field_discrepancies: @@ -111,12 +153,15 @@ def compare_structures(standard_structure: Dict[str, Any], client_structure: Dic standard_elements = standard_structure.get(element_key, []) client_elements = client_structure.get(element_key, []) - # Simplifica a comparação para ver se o cliente tem TODOS os elementos do padrão. - # Isto é uma simplificação. O ideal seria mapear por chave composta (ex: TABLE_NAME + INDEX_NAME) - - # Convertemos em strings JSON para facilitar a comparação em uma lista/set - standard_set = {json.dumps(item, sort_keys=True) for item in standard_elements} - client_set = {json.dumps(item, sort_keys=True) for item in client_elements} + # Converte em strings JSON para comparação em conjunto (Set) + try: + standard_set = {json.dumps(item, sort_keys=True) for item in standard_elements} + client_set = {json.dumps(item, sort_keys=True) for item in client_elements} + except TypeError as e: + # Caso algum elemento na lista não seja serializável (ex: None ou tipo misto) + audit_log["discrepancias_encontradas"] = True + audit_log["detalhes"]["erro_serializacao"] = f"Erro ao comparar {element_key}: {e}. Os dados podem estar malformados." + continue # Encontra elementos que estão no padrão mas não no cliente missing_elements = standard_set - client_set @@ -128,7 +173,7 @@ def compare_structures(standard_structure: Dict[str, Any], client_structure: Dic audit_log["detalhes"]["elementos_faltando"].append({ "tipo": element_key, "detalhe": "Elemento ausente", - "json_padrao": json.loads(missing_str) # Retorna o JSON de volta + "json_padrao": json.loads(missing_str) }) return audit_log