fix(repository): 扩展资源索引查询面

This commit is contained in:
2026-08-01 12:11:35 +08:00
parent 8d930bf4d7
commit a05d3ee6af
9 changed files with 436 additions and 35 deletions
+85 -11
View File
@@ -37,7 +37,7 @@ use async_trait::async_trait;
/// 资源查询条件
///
/// 用于构建灵活的资源查询。支持按类型、Hash、路径模式过滤。
/// 用于构建灵活的资源查询。支持按类型、Hash、路径、官方 release 和解析摘要过滤。
///
/// # 示例
///
@@ -56,9 +56,10 @@ use async_trait::async_trait;
/// resource_type: Some(ResourceType::AssetBundle),
/// hash: Some("abc123".to_string()),
/// path_pattern: Some("academy-*.bundle".to_string()),
/// ..ResourceQuery::all()
/// };
/// ```
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Default)]
pub struct ResourceQuery {
/// 按资源类型过滤
///
@@ -90,6 +91,41 @@ pub struct ResourceQuery {
/// - `"**/*.json"` - 匹配所有 JSON 文件
/// - `"assets/???.png"` - 匹配三个字符的 PNG 文件
pub path_pattern: Option<String>,
/// 按官方 release ID 过滤。
///
/// 匹配 `ResourceMetadata::official_release_id`。
pub official_release_id: Option<String>,
/// 按资源平台过滤。
///
/// 匹配 `ResourceMetadata::platform`,例如 `windows` 或 `android`。
pub platform: Option<String>,
/// 按官方 destination 过滤。
///
/// 匹配 `ResourceEntry::path`,用于从 release manifest destination 反查资源。
pub destination: Option<String>,
/// 按资源或所在 bundle 的官方相对路径过滤。
///
/// 匹配 `ResourceMetadata::bundle_path`。
pub bundle_path: Option<String>,
/// 按 ZIP/archive entry 过滤。
///
/// 匹配 `ResourceMetadata::archive_entries` 中的任意一项。
pub archive_entry: Option<String>,
/// 按解析状态过滤。
///
/// 匹配 `ResourceMetadata::parse_statuses` 中的任意一项。
pub parse_status: Option<String>,
/// 按 TextUnit payload format 过滤。
///
/// 匹配 `ResourceMetadata::text_unit_formats` 中的任意一项。
pub text_unit_format: Option<String>,
}
impl ResourceQuery {
@@ -105,11 +141,7 @@ impl ResourceQuery {
/// let all_resources = repo.list(ResourceQuery::all()).await?;
/// ```
pub fn all() -> Self {
Self {
resource_type: None,
hash: None,
path_pattern: None,
}
Self::default()
}
/// 按类型查询
@@ -132,8 +164,7 @@ impl ResourceQuery {
pub fn by_type(resource_type: ResourceType) -> Self {
Self {
resource_type: Some(resource_type),
hash: None,
path_pattern: None,
..Self::default()
}
}
@@ -156,11 +187,23 @@ impl ResourceQuery {
/// ```
pub fn by_hash(hash: String) -> Self {
Self {
resource_type: None,
hash: Some(hash),
path_pattern: None,
..Self::default()
}
}
/// 是否包含需要读取完整 `Resource` 后才能判断的条件。
///
/// 基础索引可先用类型、hash、路径模式和 destination 缩小范围;这些条件
/// 需要再按 metadata 过滤,确保 `list()` 与 `count()` 的语义一致。
pub fn requires_resource_scan(&self) -> bool {
self.official_release_id.is_some()
|| self.platform.is_some()
|| self.bundle_path.is_some()
|| self.archive_entry.is_some()
|| self.parse_status.is_some()
|| self.text_unit_format.is_some()
}
}
/// 资源仓储接口
@@ -305,6 +348,7 @@ pub trait ResourceRepository: Send + Sync {
/// resource_type: Some(ResourceType::AssetBundle),
/// path_pattern: Some("academy-*.bundle".to_string()),
/// hash: None,
/// ..ResourceQuery::all()
/// };
/// let filtered = repo.list(query).await?;
/// ```
@@ -416,6 +460,13 @@ mod tests {
assert!(query.resource_type.is_none());
assert!(query.hash.is_none());
assert!(query.path_pattern.is_none());
assert!(query.official_release_id.is_none());
assert!(query.platform.is_none());
assert!(query.destination.is_none());
assert!(query.bundle_path.is_none());
assert!(query.archive_entry.is_none());
assert!(query.parse_status.is_none());
assert!(query.text_unit_format.is_none());
}
/// 测试按类型查询
@@ -425,6 +476,7 @@ mod tests {
assert_eq!(query.resource_type, Some(ResourceType::AssetBundle));
assert!(query.hash.is_none());
assert!(query.path_pattern.is_none());
assert!(!query.requires_resource_scan());
}
/// 测试按 Hash 查询
@@ -434,6 +486,7 @@ mod tests {
assert_eq!(query.hash, Some("abc123".to_string()));
assert!(query.resource_type.is_none());
assert!(query.path_pattern.is_none());
assert!(!query.requires_resource_scan());
}
/// 测试组合查询
@@ -443,11 +496,32 @@ mod tests {
resource_type: Some(ResourceType::AssetBundle),
hash: Some("hash123".to_string()),
path_pattern: Some("*.bundle".to_string()),
official_release_id: Some("v-current".to_string()),
platform: Some("windows".to_string()),
destination: Some("Bundles/academy.bundle".to_string()),
bundle_path: Some("Bundles/academy.bundle".to_string()),
archive_entry: Some("academy".to_string()),
parse_status: Some("parsed".to_string()),
text_unit_format: Some("json".to_string()),
};
assert_eq!(query.resource_type, Some(ResourceType::AssetBundle));
assert_eq!(query.hash, Some("hash123".to_string()));
assert_eq!(query.path_pattern, Some("*.bundle".to_string()));
assert_eq!(query.official_release_id, Some("v-current".to_string()));
assert_eq!(query.platform, Some("windows".to_string()));
assert_eq!(
query.destination,
Some("Bundles/academy.bundle".to_string())
);
assert_eq!(
query.bundle_path,
Some("Bundles/academy.bundle".to_string())
);
assert_eq!(query.archive_entry, Some("academy".to_string()));
assert_eq!(query.parse_status, Some("parsed".to_string()));
assert_eq!(query.text_unit_format, Some("json".to_string()));
assert!(query.requires_resource_scan());
}
/// 测试 ResourceQuery 可以被克隆