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 56e3dce..e28cb2d 100644 --- a/packages/v1/administrativo/services/log/log_show_database_service.py +++ b/packages/v1/administrativo/services/log/log_show_database_service.py @@ -1,5 +1,6 @@ from fastapi import HTTPException, status import json +from typing import Dict, Any, List # NOTE: O esquema de entrada para a ação de exibição de um único log # precisaria de um esquema (Schema) que carregue o 'log_id'. @@ -8,49 +9,129 @@ from packages.v1.administrativo.schemas.log_schema import LogClientIdSchema from packages.v1.administrativo.actions.log.log_show_database_action import ShowDatabaseAction -# --- NOVA FUNÇÃO AUXILIAR DE COMPARAÇÃO --- -def compare_structures(standard_structure: dict, client_structure: dict) -> dict: +# Função auxiliar para comparação de campos +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} + + # 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 field_name not in client_fields_map: + # Campo que existe no padrão mas não no cliente + discrepancies.append({ + "tabela": table_name, + "tipo": "Campo Faltando", + "detalhe": f"Campo '{field_name}' ausente na tabela do cliente.", + "padrao": standard_field, + "cliente": None + }) + continue + + # 3. Comparar atributos do campo (tipo, nulidade, default) + client_field = client_fields_map[field_name] + + # Lista de atributos cruciais para comparação + attributes_to_check = ['DATA_TYPE', 'NULLABLE', 'DEFAULT'] + + for attr in attributes_to_check: + 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.). + if standard_value != client_value: + discrepancies.append({ + "tabela": table_name, + "tipo": f"Atributo Divergente ({attr})", + "detalhe": f"Atributo '{attr}' do campo '{field_name}' não coincide.", + "padrao": standard_value, + "cliente": client_value + }) + + return discrepancies + + +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. - ESTA FUNÇÃO DEVE SER IMPLEMENTADA COM A LÓGICA DE NEGÓCIO COMPLETA. - O exemplo abaixo é uma simulação básica de comparação de tabelas. """ - discrepancies = { + audit_log = { "discrepancias_encontradas": False, - "detalhes": {} + "detalhes": { + "tabelas_faltando": [], + "elementos_faltando": [], # Para PKs, FKs, Views, etc. + "divergencia_de_campos": [] # Para divergências dentro das tabelas + } } - # Se a estrutura padrão estiver vazia, não há como comparar. - if not standard_structure: - discrepancies["detalhes"]["erro_comparacao"] = "Estrutura padrão de referência não encontrada ou está vazia." - return discrepancies + if not standard_structure or not client_structure: + audit_log["detalhes"]["erro"] = "Estrutura padrão ou do cliente indisponível para comparação." + audit_log["discrepancias_encontradas"] = True + return audit_log + + # Mapear tabelas padrão e cliente por nome + 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. AUDITORIA DE TABELAS E SEUS CAMPOS --- + + # 1.1 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. Comparação de Tabelas - try: - standard_tables = {item["TABLE_NAME"]: item for item in standard_structure.get("tables", [])} - client_tables = {item["TABLE_NAME"]: item for item in client_structure.get("tables", [])} - - missing_tables = standard_tables.keys() - client_tables.keys() - - if missing_tables: - discrepancies["discrepancias_encontradas"] = True - discrepancies["detalhes"]["tabelas_faltando"] = list(missing_tables) + # 1.2 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] - # Adicione aqui a lógica para verificar campos, PKs, FKs, etc. - # Exemplo: Verificar se os campos da tabela 'CLIENTES' estão no cliente - # if 'CLIENTES' in standard_tables and 'CLIENTES' in client_tables: - # standard_fields = standard_tables['CLIENTES']['FIELDS'] # Assumindo um formato mais detalhado - # client_fields = client_tables['CLIENTES']['FIELDS'] - # # ... lógica de comparação de campos + # Assume que os campos são listados sob a chave 'FIELDS' + standard_fields = standard_table.get('FIELDS', []) + client_fields = client_table.get('FIELDS', []) - except Exception as e: - # Em caso de erro na estrutura JSON (malformada) - discrepancies["discrepancias_encontradas"] = True - discrepancies["detalhes"]["erro_processamento"] = f"Erro ao processar estruturas para comparação: {e}" + field_discrepancies = compare_fields(standard_fields, client_fields, table_name) + + if field_discrepancies: + audit_log["discrepancias_encontradas"] = True + audit_log["detalhes"]["divergencia_de_campos"].extend(field_discrepancies) + # --- 2. AUDITORIA DE OUTROS ELEMENTOS (PKs, FKs, etc.) --- + + 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, []) + + # 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} + + # Encontra elementos que estão no padrão mas não no cliente + missing_elements = standard_set - client_set + + if missing_elements: + audit_log["discrepancias_encontradas"] = True + + for missing_str in missing_elements: + audit_log["detalhes"]["elementos_faltando"].append({ + "tipo": element_key, + "detalhe": "Elemento ausente", + "json_padrao": json.loads(missing_str) # Retorna o JSON de volta + }) - return discrepancies -# --- FIM DA NOVA FUNÇÃO AUXILIAR DE COMPARAÇÃO --- + return audit_log class ShowDatabaseService: