fix: 修复工作流模板JSON解析错误
- 添加 WorkflowType 的 From<String> 实现,支持从字符串转换 - 修复 workflow_template_repository 中的JSON字段解析,处理空字符串情况 - 为所有JSON字段(comfyui_workflow_json, ui_config_json, execution_config_json等)添加空字符串检查 - 添加详细的数据库调试测试,帮助诊断JSON解析问题 - 修复 WorkflowTemplateFilter 添加缺失的 search_term 字段 主要修复: 1. JSON解析:当JSON字段为空字符串时,返回空对象而不是解析错误 2. 类型转换:WorkflowType 现在可以从数据库字符串直接转换 3. 错误处理:改进了JSON解析的错误处理逻辑 4. 测试工具:添加了详细的数据库内容检查和逐字段解析测试 这些修复解决了前端 WorkflowList.tsx 中的 'premature end of input' JSON解析错误。
This commit is contained in:
parent
4af81a662d
commit
2d3c44d5e9
|
|
@ -474,42 +474,65 @@ impl WorkflowTemplateRepository {
|
|||
|
||||
// 解析工作流类型
|
||||
let type_str: String = row.get("type")?;
|
||||
let workflow_type: WorkflowType = serde_json::from_str(&type_str)
|
||||
.map_err(|e| rusqlite::Error::FromSqlConversionFailure(
|
||||
0, rusqlite::types::Type::Text, Box::new(e)
|
||||
))?;
|
||||
let workflow_type: WorkflowType = WorkflowType::from(type_str);
|
||||
|
||||
let description: Option<String> = row.get("description")?;
|
||||
|
||||
// 解析JSON字段
|
||||
// 解析JSON字段,处理空字符串的情况
|
||||
let comfyui_workflow_json_str: String = row.get("comfyui_workflow_json")?;
|
||||
let comfyui_workflow_json: serde_json::Value = serde_json::from_str(&comfyui_workflow_json_str)
|
||||
let comfyui_workflow_json: serde_json::Value = if comfyui_workflow_json_str.trim().is_empty() {
|
||||
serde_json::Value::Object(serde_json::Map::new())
|
||||
} else {
|
||||
serde_json::from_str(&comfyui_workflow_json_str)
|
||||
.map_err(|e| rusqlite::Error::FromSqlConversionFailure(
|
||||
0, rusqlite::types::Type::Text, Box::new(e)
|
||||
))?;
|
||||
))?
|
||||
};
|
||||
|
||||
let ui_config_json_str: String = row.get("ui_config_json")?;
|
||||
let ui_config_json: serde_json::Value = serde_json::from_str(&ui_config_json_str)
|
||||
let ui_config_json: serde_json::Value = if ui_config_json_str.trim().is_empty() {
|
||||
serde_json::Value::Object(serde_json::Map::new())
|
||||
} else {
|
||||
serde_json::from_str(&ui_config_json_str)
|
||||
.map_err(|e| rusqlite::Error::FromSqlConversionFailure(
|
||||
0, rusqlite::types::Type::Text, Box::new(e)
|
||||
))?;
|
||||
))?
|
||||
};
|
||||
|
||||
let execution_config_json: Option<serde_json::Value> = row.get::<_, Option<String>>("execution_config_json")?
|
||||
.map(|s| serde_json::from_str(&s))
|
||||
.map(|s| {
|
||||
if s.trim().is_empty() {
|
||||
Ok(serde_json::Value::Object(serde_json::Map::new()))
|
||||
} else {
|
||||
serde_json::from_str(&s)
|
||||
}
|
||||
})
|
||||
.transpose()
|
||||
.map_err(|e| rusqlite::Error::FromSqlConversionFailure(
|
||||
0, rusqlite::types::Type::Text, Box::new(e)
|
||||
))?;
|
||||
|
||||
let input_schema_json: Option<serde_json::Value> = row.get::<_, Option<String>>("input_schema_json")?
|
||||
.map(|s| serde_json::from_str(&s))
|
||||
.map(|s| {
|
||||
if s.trim().is_empty() {
|
||||
Ok(serde_json::Value::Object(serde_json::Map::new()))
|
||||
} else {
|
||||
serde_json::from_str(&s)
|
||||
}
|
||||
})
|
||||
.transpose()
|
||||
.map_err(|e| rusqlite::Error::FromSqlConversionFailure(
|
||||
0, rusqlite::types::Type::Text, Box::new(e)
|
||||
))?;
|
||||
|
||||
let output_schema_json: Option<serde_json::Value> = row.get::<_, Option<String>>("output_schema_json")?
|
||||
.map(|s| serde_json::from_str(&s))
|
||||
.map(|s| {
|
||||
if s.trim().is_empty() {
|
||||
Ok(serde_json::Value::Object(serde_json::Map::new()))
|
||||
} else {
|
||||
serde_json::from_str(&s)
|
||||
}
|
||||
})
|
||||
.transpose()
|
||||
.map_err(|e| rusqlite::Error::FromSqlConversionFailure(
|
||||
0, rusqlite::types::Type::Text, Box::new(e)
|
||||
|
|
|
|||
|
|
@ -136,3 +136,171 @@ fn test_json_operations() {
|
|||
assert_eq!(json_value["value"], 42);
|
||||
assert_eq!(json_value["active"], true);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_database_connection() {
|
||||
use crate::infrastructure::database::Database;
|
||||
|
||||
// 测试数据库连接
|
||||
let database = Database::new().expect("应该能够创建数据库连接");
|
||||
|
||||
// 运行迁移
|
||||
database.run_migrations().expect("应该能够运行数据库迁移");
|
||||
|
||||
// 测试查询工作流模板表
|
||||
let conn = database.get_connection();
|
||||
let conn = conn.lock().unwrap();
|
||||
|
||||
// 检查表是否存在
|
||||
let mut stmt = conn.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='workflow_templates'")
|
||||
.expect("应该能够准备查询语句");
|
||||
|
||||
let table_exists = stmt.exists([]).expect("应该能够检查表是否存在");
|
||||
assert!(table_exists, "workflow_templates 表应该存在");
|
||||
|
||||
// 检查表结构
|
||||
let mut stmt = conn.prepare("PRAGMA table_info(workflow_templates)")
|
||||
.expect("应该能够准备表结构查询");
|
||||
|
||||
let column_count = stmt.query_map([], |row| {
|
||||
Ok(row.get::<_, String>(1)?) // 获取列名
|
||||
}).expect("应该能够查询表结构")
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.expect("应该能够收集列信息")
|
||||
.len();
|
||||
|
||||
assert!(column_count > 0, "workflow_templates 表应该有列");
|
||||
println!("数据库连接测试通过,workflow_templates 表有 {} 列", column_count);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_workflow_template_repository() {
|
||||
use crate::data::repositories::workflow_template_repository::WorkflowTemplateRepository;
|
||||
use crate::infrastructure::database::Database;
|
||||
use std::sync::Arc;
|
||||
|
||||
// 创建数据库和仓库
|
||||
let database = Arc::new(Database::new().expect("应该能够创建数据库"));
|
||||
database.run_migrations().expect("应该能够运行迁移");
|
||||
|
||||
// 首先检查数据库中的原始数据
|
||||
let conn = database.get_connection();
|
||||
let conn = conn.lock().unwrap();
|
||||
|
||||
// 检查表中是否有数据
|
||||
let count: i64 = conn.query_row("SELECT COUNT(*) FROM workflow_templates", [], |row| {
|
||||
row.get(0)
|
||||
}).expect("应该能够查询记录数量");
|
||||
|
||||
println!("数据库中有 {} 条工作流模板记录", count);
|
||||
|
||||
if count > 0 {
|
||||
// 检查第一条记录的所有字段
|
||||
let mut stmt = conn.prepare("SELECT * FROM workflow_templates LIMIT 1")
|
||||
.expect("应该能够准备查询语句");
|
||||
|
||||
let result = stmt.query_row([], |row| {
|
||||
println!("第一条记录的所有字段:");
|
||||
for i in 0..row.as_ref().column_count() {
|
||||
let column_name = row.as_ref().column_name(i).unwrap_or("unknown");
|
||||
match row.get_ref(i) {
|
||||
Ok(value) => {
|
||||
match value {
|
||||
rusqlite::types::ValueRef::Null => println!(" {}: NULL", column_name),
|
||||
rusqlite::types::ValueRef::Integer(v) => println!(" {}: {}", column_name, v),
|
||||
rusqlite::types::ValueRef::Real(v) => println!(" {}: {}", column_name, v),
|
||||
rusqlite::types::ValueRef::Text(v) => {
|
||||
let text = std::str::from_utf8(v).unwrap_or("invalid utf8");
|
||||
if text.len() > 100 {
|
||||
println!(" {}: {} chars, preview: {:?}", column_name, text.len(), &text[..100]);
|
||||
} else {
|
||||
println!(" {}: {:?}", column_name, text);
|
||||
}
|
||||
},
|
||||
rusqlite::types::ValueRef::Blob(v) => println!(" {}: blob {} bytes", column_name, v.len()),
|
||||
}
|
||||
},
|
||||
Err(e) => println!(" {}: ERROR - {}", column_name, e),
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
});
|
||||
|
||||
if let Err(e) = result {
|
||||
println!("查询第一条记录失败: {}", e);
|
||||
}
|
||||
}
|
||||
|
||||
drop(conn); // 释放连接
|
||||
|
||||
// 现在测试手动解析第一条记录
|
||||
if count > 0 {
|
||||
let conn = database.get_connection();
|
||||
let conn = conn.lock().unwrap();
|
||||
|
||||
let mut stmt = conn.prepare("SELECT * FROM workflow_templates LIMIT 1")
|
||||
.expect("应该能够准备查询语句");
|
||||
|
||||
let result = stmt.query_row([], |row| {
|
||||
println!("开始手动解析记录...");
|
||||
|
||||
// 逐个字段解析,找出问题所在
|
||||
let id: Option<i64> = Some(row.get("id")?);
|
||||
println!("✓ ID: {:?}", id);
|
||||
|
||||
let name: String = row.get("name")?;
|
||||
println!("✓ Name: {}", name);
|
||||
|
||||
let base_name: String = row.get("base_name")?;
|
||||
println!("✓ Base name: {}", base_name);
|
||||
|
||||
let version: String = row.get("version")?;
|
||||
println!("✓ Version: {}", version);
|
||||
|
||||
let type_str: String = row.get("type")?;
|
||||
println!("✓ Type: {}", type_str);
|
||||
|
||||
let description: Option<String> = row.get("description")?;
|
||||
println!("✓ Description: {:?}", description);
|
||||
|
||||
// 测试JSON字段解析
|
||||
let comfyui_workflow_json_str: String = row.get("comfyui_workflow_json")?;
|
||||
println!("✓ ComfyUI JSON string length: {}", comfyui_workflow_json_str.len());
|
||||
|
||||
// 尝试解析JSON
|
||||
match serde_json::from_str::<serde_json::Value>(&comfyui_workflow_json_str) {
|
||||
Ok(json) => println!("✓ ComfyUI JSON parsed successfully"),
|
||||
Err(e) => println!("✗ ComfyUI JSON parse error: {}", e),
|
||||
}
|
||||
|
||||
let ui_config_json_str: String = row.get("ui_config_json")?;
|
||||
println!("✓ UI Config JSON string length: {}", ui_config_json_str.len());
|
||||
|
||||
match serde_json::from_str::<serde_json::Value>(&ui_config_json_str) {
|
||||
Ok(json) => println!("✓ UI Config JSON parsed successfully"),
|
||||
Err(e) => println!("✗ UI Config JSON parse error: {}", e),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
});
|
||||
|
||||
if let Err(e) = result {
|
||||
println!("手动解析失败: {}", e);
|
||||
}
|
||||
|
||||
drop(conn);
|
||||
}
|
||||
|
||||
let repo = WorkflowTemplateRepository::new(database);
|
||||
|
||||
// 测试查询所有模板(应该返回空列表而不是错误)
|
||||
match repo.find_all(None) {
|
||||
Ok(templates) => {
|
||||
println!("成功查询工作流模板,数量: {}", templates.len());
|
||||
// 空列表是正常的,因为还没有插入数据
|
||||
},
|
||||
Err(e) => {
|
||||
panic!("查询工作流模板失败: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue