feat(plugin): PluginRelation 级联删除声明 + OnDeleteStrategy
新增 OnDeleteStrategy 枚举(Nullify/Cascade/Restrict)和 PluginRelation 结构体声明实体关联关系。PluginEntity 增加 relations 字段(serde(default) 向后兼容)。
This commit is contained in:
@@ -956,6 +956,7 @@ mod tests {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
indexes: vec![],
|
indexes: vec![],
|
||||||
|
relations: vec![],
|
||||||
};
|
};
|
||||||
|
|
||||||
let sql = DynamicTableManager::build_create_table_sql("erp_crm", &entity);
|
let sql = DynamicTableManager::build_create_table_sql("erp_crm", &entity);
|
||||||
@@ -996,6 +997,7 @@ mod tests {
|
|||||||
..PluginField::default_for_field()
|
..PluginField::default_for_field()
|
||||||
}],
|
}],
|
||||||
indexes: vec![],
|
indexes: vec![],
|
||||||
|
relations: vec![],
|
||||||
};
|
};
|
||||||
|
|
||||||
let sql = DynamicTableManager::build_create_table_sql("erp_crm", &entity);
|
let sql = DynamicTableManager::build_create_table_sql("erp_crm", &entity);
|
||||||
|
|||||||
@@ -43,6 +43,8 @@ pub struct PluginEntity {
|
|||||||
pub fields: Vec<PluginField>,
|
pub fields: Vec<PluginField>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub indexes: Vec<PluginIndex>,
|
pub indexes: Vec<PluginIndex>,
|
||||||
|
#[serde(default)]
|
||||||
|
pub relations: Vec<PluginRelation>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 字段校验规则
|
/// 字段校验规则
|
||||||
@@ -156,6 +158,23 @@ pub struct PluginIndex {
|
|||||||
pub unique: bool,
|
pub unique: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 级联删除策略
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
|
pub enum OnDeleteStrategy {
|
||||||
|
Nullify, // 置空外键字段
|
||||||
|
Cascade, // 级联软删除
|
||||||
|
Restrict, // 存在关联时拒绝删除
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 实体关联关系声明
|
||||||
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
|
pub struct PluginRelation {
|
||||||
|
pub entity: String,
|
||||||
|
pub foreign_key: String,
|
||||||
|
pub on_delete: OnDeleteStrategy,
|
||||||
|
}
|
||||||
|
|
||||||
/// 事件订阅配置
|
/// 事件订阅配置
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct PluginEvents {
|
pub struct PluginEvents {
|
||||||
@@ -690,4 +709,41 @@ no_cycle = true
|
|||||||
assert_eq!(field.no_cycle, Some(true));
|
assert_eq!(field.no_cycle, Some(true));
|
||||||
assert_eq!(field.ref_entity.as_deref(), Some("customer"));
|
assert_eq!(field.ref_entity.as_deref(), Some("customer"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_entity_with_relations() {
|
||||||
|
let toml = r#"
|
||||||
|
[metadata]
|
||||||
|
id = "test"
|
||||||
|
name = "Test"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
|
[schema]
|
||||||
|
[[schema.entities]]
|
||||||
|
name = "customer"
|
||||||
|
display_name = "客户"
|
||||||
|
|
||||||
|
[[schema.entities.fields]]
|
||||||
|
name = "code"
|
||||||
|
field_type = "string"
|
||||||
|
required = true
|
||||||
|
display_name = "编码"
|
||||||
|
|
||||||
|
[[schema.entities.relations]]
|
||||||
|
entity = "contact"
|
||||||
|
foreign_key = "customer_id"
|
||||||
|
on_delete = "cascade"
|
||||||
|
|
||||||
|
[[schema.entities.relations]]
|
||||||
|
entity = "customer_tag"
|
||||||
|
foreign_key = "customer_id"
|
||||||
|
on_delete = "cascade"
|
||||||
|
"#;
|
||||||
|
let manifest = parse_manifest(toml).unwrap();
|
||||||
|
let entity = &manifest.schema.unwrap().entities[0];
|
||||||
|
assert_eq!(entity.relations.len(), 2);
|
||||||
|
assert_eq!(entity.relations[0].entity, "contact");
|
||||||
|
assert_eq!(entity.relations[0].foreign_key, "customer_id");
|
||||||
|
assert!(matches!(entity.relations[0].on_delete, OnDeleteStrategy::Cascade));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user