From fe2803f3da6af5b3677df21eccf3c04f4807e851 Mon Sep 17 00:00:00 2001 From: YoVinchen Date: Thu, 14 Aug 2025 16:32:44 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20=E9=83=A8=E5=88=86=20json?= =?UTF-8?q?=20=E6=95=B0=E6=8D=AE=E4=B8=8D=E8=83=BD=E8=AF=86=E5=88=AB=20?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=20=E6=A0=87=E7=AD=BE=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=E6=AF=94=E5=AF=B9=E4=B8=8D=E5=AE=8C=E5=85=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- modules/api_routes.py | 11 ++++++-- modules/config_manager.py | 33 ++++++++++++++++++++++ modules/data_comparison.py | 58 ++++++++++++++++++++++++++++++++++---- 3 files changed, 93 insertions(+), 9 deletions(-) diff --git a/modules/api_routes.py b/modules/api_routes.py index acd6929..0edefc8 100644 --- a/modules/api_routes.py +++ b/modules/api_routes.py @@ -20,7 +20,8 @@ from .config_manager import ( save_redis_query_history, get_redis_query_history, get_redis_query_history_by_id, delete_redis_query_history, batch_delete_redis_query_history, - parse_redis_config_from_yaml + parse_redis_config_from_yaml, + convert_bytes_to_str # 添加bytes转换函数 ) from .cassandra_client import create_connection from .query_engine import execute_query, execute_mixed_query @@ -266,6 +267,8 @@ def setup_routes(app, query_log_collector): # 结束查询批次 query_log_collector.end_current_batch() + # 转换result中可能包含的bytes类型数据 + result = convert_bytes_to_str(result) return jsonify(result) except Exception as e: @@ -421,6 +424,8 @@ def setup_routes(app, query_log_collector): # 结束查询批次 query_log_collector.end_current_batch() + # 转换result中可能包含的bytes类型数据 + result = convert_bytes_to_str(result) return jsonify(result) except Exception as e: @@ -1217,7 +1222,7 @@ def setup_routes(app, query_log_collector): # 过滤每个批次中的日志,只保留Redis相关的 redis_logs = [ log for log in logs - if log.get('query_type') == 'redis' or + if log.get('query_type', '').lower() == 'redis' or (log.get('message') and 'redis' in log.get('message', '').lower()) ] if redis_logs: # 只有当批次中有Redis日志时才添加 @@ -1239,7 +1244,7 @@ def setup_routes(app, query_log_collector): # 过滤Redis相关的日志 redis_logs = [ log for log in logs - if log.get('query_type') == 'redis' or + if log.get('query_type', '').lower() == 'redis' or (log.get('message') and 'redis' in log.get('message', '').lower()) ] diff --git a/modules/config_manager.py b/modules/config_manager.py index fd9cdfe..af228a4 100644 --- a/modules/config_manager.py +++ b/modules/config_manager.py @@ -39,6 +39,31 @@ from .database import ensure_database, get_db_connection logger = logging.getLogger(__name__) +def convert_bytes_to_str(obj): + """递归转换对象中的bytes类型为字符串,用于JSON序列化 + + Args: + obj: 需要转换的对象(可以是dict, list或其他类型) + + Returns: + 转换后的对象,所有bytes类型都被转换为hex字符串 + """ + if isinstance(obj, bytes): + # 将bytes转换为十六进制字符串 + return obj.hex() + elif isinstance(obj, dict): + # 递归处理字典 + return {key: convert_bytes_to_str(value) for key, value in obj.items()} + elif isinstance(obj, list): + # 递归处理列表 + return [convert_bytes_to_str(item) for item in obj] + elif isinstance(obj, tuple): + # 递归处理元组 + return tuple(convert_bytes_to_str(item) for item in obj) + else: + # 其他类型直接返回 + return obj + # Cassandra数据库默认配置模板 # 注意:此配置不包含敏感信息,仅作为UI表单的初始模板使用 DEFAULT_CONFIG = { @@ -233,6 +258,9 @@ def save_redis_query_history(name, description, cluster1_config, cluster2_config cursor = conn.cursor() try: + # 转换可能包含bytes类型的数据 + raw_results = convert_bytes_to_str(raw_results) if raw_results else None + cursor.execute(''' INSERT INTO redis_query_history (name, description, cluster1_config, cluster2_config, query_options, query_keys, @@ -600,6 +628,11 @@ def save_query_history(name, description, pro_config, test_config, query_config, cursor = conn.cursor() try: + # 转换可能包含bytes类型的数据 + raw_results = convert_bytes_to_str(raw_results) if raw_results else None + differences_data = convert_bytes_to_str(differences_data) if differences_data else None + identical_data = convert_bytes_to_str(identical_data) if identical_data else None + cursor.execute(''' INSERT INTO query_history (name, description, pro_config, test_config, query_config, query_keys, diff --git a/modules/data_comparison.py b/modules/data_comparison.py index 5bd554d..e0b041b 100644 --- a/modules/data_comparison.py +++ b/modules/data_comparison.py @@ -86,8 +86,8 @@ def compare_results(pro_data, test_data, keys, fields_to_compare, exclude_fields value_pro = getattr(row_pro, column) value_test = getattr(row_test, column) - # 使用智能比较函数 - if not compare_values(value_pro, value_test): + # 使用智能比较函数,传递字段名用于标签字段判断 + if not compare_values(value_pro, value_test, column): has_difference = True # 格式化显示值 formatted_pro_value = format_json_for_display(value_pro) @@ -99,7 +99,8 @@ def compare_results(pro_data, test_data, keys, fields_to_compare, exclude_fields 'pro_value': formatted_pro_value, 'test_value': formatted_test_value, 'is_json': is_json_field(value_pro) or is_json_field(value_test), - 'is_array': is_json_array_field(value_pro) or is_json_array_field(value_test) + 'is_array': is_json_array_field(value_pro) or is_json_array_field(value_test), + 'is_tag': is_tag_field(column, value_pro) or is_tag_field(column, value_test) }) # 统计字段差异次数 @@ -307,9 +308,54 @@ def is_json_field(value): except (json.JSONDecodeError, TypeError): return False -def compare_values(value1, value2): - """智能比较两个值,支持JSON标准化和数组比较""" - # 首先检查是否为数组类型 +def is_tag_field(field_name, value): + """判断是否为标签类字段(空格分隔的标签列表) + + 标签字段特征: + 1. 字段名包含 'tag' 关键字 + 2. 值是字符串类型 + 3. 包含空格分隔的多个元素 + """ + if not isinstance(value, str): + return False + + # 检查字段名是否包含tag + if field_name and 'tag' in field_name.lower(): + # 检查是否包含空格分隔的多个元素 + elements = value.strip().split() + if len(elements) > 1: + return True + + return False + +def compare_tag_values(value1, value2): + """比较标签类字段的值(忽略顺序) + + 将空格分隔的标签字符串拆分成集合进行比较 + """ + if not isinstance(value1, str) or not isinstance(value2, str): + return value1 == value2 + + # 将标签字符串拆分成集合 + tags1 = set(value1.strip().split()) + tags2 = set(value2.strip().split()) + + # 比较集合是否相等(忽略顺序) + return tags1 == tags2 + +def compare_values(value1, value2, field_name=None): + """智能比较两个值,支持JSON标准化、数组比较和标签比较 + + Args: + value1: 第一个值 + value2: 第二个值 + field_name: 字段名(可选,用于判断是否为标签字段) + """ + # 检查是否为标签字段 + if field_name and (is_tag_field(field_name, value1) or is_tag_field(field_name, value2)): + return compare_tag_values(value1, value2) + + # 检查是否为数组类型 if is_json_array_field(value1) or is_json_array_field(value2): return compare_array_values(value1, value2)