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 e656198..642ca9c 100644 --- a/packages/v1/administrativo/services/log/log_show_database_service.py +++ b/packages/v1/administrativo/services/log/log_show_database_service.py @@ -71,6 +71,82 @@ 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 +# --- 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]: + """ + Identifica elementos presentes na estrutura PADRÃO mas ausentes na estrutura CLIENTE. + (Operação: Standard - Client) + Assume que as estruturas de entrada já estão com as chaves em UPPERCASE. + """ + standard_only = {} + + # --- 1. TABLES --- + + # 1a. Nomes de Tabelas Cliente (para comparação de unicidade) + client_tables_names = {t.get('TABLE_NAME') for t in client_structure.get('TABLES', []) + if t.get('TABLE_NAME') and not is_ignored(t.get('TABLE_NAME'))} + + # 1b. Agrupa Campos do Padrão por Nome de Tabela + standard_fields_by_table: Dict[str, List[Dict]] = {} + for field_item in standard_structure.get('TABLES', []): + table_name = field_item.get('TABLE_NAME') + if table_name and not is_ignored(table_name): + if table_name not in standard_fields_by_table: + standard_fields_by_table[table_name] = [] + standard_fields_by_table[table_name].append(field_item) + + # 1c. Encontra Tabelas Exclusivas do Padrão + standard_tables_names = set(standard_fields_by_table.keys()) + + # Diferença: Tabelas Padrão - Tabelas Cliente + unique_table_names = standard_tables_names - client_tables_names + + standard_only_tables = [] + for table_name in unique_table_names: + standard_only_tables.append({ + "TABLE_NAME": table_name, + "FIELDS": [_remove_source_code(f) for f in standard_fields_by_table[table_name]] + }) + + if standard_only_tables: + standard_only["TABELAS_UNICAS"] = standard_only_tables + + # --- 2. 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, []) + + # Standard Set (Mapeamento para reobter o objeto limpo) + standard_set_normalized = {} + for item in standard_elements: + identifier = get_element_identifier(item) + if identifier and not is_ignored(identifier): + cleaned_item = _remove_source_code(item) + json_str = json.dumps(cleaned_item, sort_keys=True) + standard_set_normalized[json_str] = cleaned_item + + standard_set = set(standard_set_normalized.keys()) + + # Client Set (Basta o set dos JSON strings) + client_elements_filtered = [item for item in client_elements + if not is_ignored(get_element_identifier(item))] + client_set = {json.dumps(_remove_source_code(item), sort_keys=True) + for item in client_elements_filtered} + + # Calcula a diferença Padrão - Cliente + unique_standard_elements_str = standard_set - client_set + + if unique_standard_elements_str: + standard_only[element_key + "_UNICOS"] = [ + standard_set_normalized[json_str] for json_str in unique_standard_elements_str + ] + + return standard_only + # --- FUNÇÃO: ELEMENTOS SOMENTE NO CLIENTE (Agora usa chaves UPPERCASE) --- @@ -184,10 +260,10 @@ class ShowDatabaseService: dados_json = log_show_database_action.execute(client_id_schema) - if dados_json and dados_json.get("file"): + if dados_json and dados_json.get("file"): # Extrai e carrega os dados JSON do campo 'file' - dados_json = json.loads(dados_json["file"]) + dados_json = json.loads(dados_json["file"]) # Extrai as estruturas de dados relevantes standard_structure_json_string = dados_json.get("standard_structure_json") @@ -200,7 +276,7 @@ class ShowDatabaseService: # Extrai a estrutura do cliente do JSON database_data = dados_json.get("database", {}) - client_structure: Dict[str, Any] = database_data.get("structure", {}) + client_structure: Dict[str, Any] = database_data.get("structure", {}) # NOVO PASSO CRUCIAL: Normaliza as chaves para UPPERCASE em ambas as estruturas standard_structure_data = _normalize_keys_to_upper(standard_structure_data) @@ -215,10 +291,16 @@ class ShowDatabaseService: 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", {}) - + partition_info = database_data.get("partition", {}) + # Monta o JSON final data = { "cns": dados_json.get("cns"), @@ -229,12 +311,13 @@ class ShowDatabaseService: "partition": partition_info, "default_schema": debug_padrao, "client_schema": debug_cliente, - "client_only_items": elementos_unicos_cliente + "client_only_items": elementos_unicos_cliente, + "standard_only_items": elementos_unicos_padrao # NOVO CAMPO ADICIONADO } - } + } # Retorna o json com os dados - return data + return data else: raise HTTPException(