feat: 收口 Rust Web 3000 主链

This commit is contained in:
lix-2026
2026-05-11 13:16:34 +08:00
parent 7f3f7d4e2f
commit 17c003976b
61 changed files with 2090 additions and 2256 deletions
@@ -455,6 +455,114 @@ pub fn read_stream_cursor_from_payload(payload: &Value) -> Option<String> {
read_string_field(payload, &["cursor"])
}
fn attach_workspace_dataset_projections(
mut dataset: Value,
sidebar_projection: Value,
file_tree_projection: Value,
) -> Value {
let Some(map) = dataset.as_object_mut() else {
return dataset;
};
map.insert(
"kernel_sidebar_projection".into(),
sidebar_projection.clone(),
);
map.insert("kernelSidebarProjection".into(), sidebar_projection);
map.insert(
"kernel_file_tree_projection".into(),
file_tree_projection.clone(),
);
map.insert("kernelFileTreeProjection".into(), file_tree_projection);
dataset
}
async fn load_workspace_stream_snapshot(
config: &AppConfig,
context: &RequestContext,
workspace_id: &str,
depth: Option<u32>,
) -> Result<Value, WebError> {
let sidebar_loaded = load_projection_snapshot(
config,
context,
&ProjectionSnapshotSpec {
workspace_id,
root_node_id: None,
depth,
query: None,
max_results: None,
projection: KernelProjectionKind::SidebarTree,
},
)
.await?;
let file_tree_loaded = load_projection_snapshot(
config,
context,
&ProjectionSnapshotSpec {
workspace_id,
root_node_id: None,
depth,
query: None,
max_results: None,
projection: KernelProjectionKind::FileTree,
},
)
.await?;
let dataset = attach_workspace_dataset_projections(
sidebar_loaded.dataset,
sidebar_loaded.projection.clone(),
file_tree_loaded.projection,
);
Ok(json!({
"dataset": dataset,
"tree": sidebar_loaded.projection,
}))
}
fn delta_document_patch_is_title_only(candidate: &Value) -> bool {
let Some(map) = candidate.as_object() else {
return false;
};
map.keys().all(|key| {
matches!(
key.as_str(),
"id" | "documentId" | "title" | "updatedAt" | "updated_at"
)
})
}
fn delta_requires_projection_snapshot(delta: &Value) -> bool {
let Some(map) = delta.as_object() else {
return false;
};
let op = map
.get("op")
.and_then(Value::as_str)
.map(str::trim)
.unwrap_or("");
if op.is_empty() || op == "noop" {
return false;
}
if op == "upsert_document" {
return !map
.get("node")
.or_else(|| map.get("document"))
.is_some_and(delta_document_patch_is_title_only);
}
if op == "upsert_documents" {
let Some(items) = map
.get("upsertDocuments")
.or_else(|| map.get("upsert_documents"))
.and_then(Value::as_array)
else {
return true;
};
return !items.iter().all(delta_document_patch_is_title_only);
}
true
}
pub fn with_stream_kind(payload: &Value, kind: &str) -> Value {
if let Some(mut map) = payload.as_object().cloned() {
map.insert("kind".into(), Value::String(kind.into()));
@@ -466,16 +574,23 @@ pub fn with_stream_kind(payload: &Value, kind: &str) -> Value {
})
}
pub fn build_stream_delta_payload(
pub async fn build_stream_delta_payload(
config: &AppConfig,
context: &RequestContext,
query: &StreamSnapshotQuery,
workspace_id: &str,
overview: &Value,
cursor: Option<String>,
delta: Value,
) -> Value {
) -> Result<Value, WebError> {
let scope = resolve_stream_scope(query);
json!({
let snapshot =
if scope == StreamSnapshotScope::Workspace && delta_requires_projection_snapshot(&delta) {
load_workspace_stream_snapshot(config, context, workspace_id, query.depth).await?
} else {
Value::Null
};
Ok(json!({
"kind": "delta",
"revision": cursor.clone().unwrap_or_else(|| "0".into()),
"stream": scope.as_str(),
@@ -487,9 +602,9 @@ pub fn build_stream_delta_payload(
"depth": query.depth,
"cursor": cursor,
"data": delta,
"snapshot": Value::Null,
"snapshot": snapshot,
"overview": overview,
})
}))
}
pub async fn load_stream_overview(
@@ -522,24 +637,8 @@ pub async fn load_stream_snapshot(
let snapshot = match scope {
StreamSnapshotScope::Workspace => {
let loaded = load_projection_snapshot(
config,
context,
&ProjectionSnapshotSpec {
workspace_id: &effective_workspace_id,
root_node_id: None,
depth: query.depth,
query: None,
max_results: None,
projection: KernelProjectionKind::SidebarTree,
},
)
.await?;
json!({
"dataset": loaded.dataset,
"tree": loaded.projection,
})
load_workspace_stream_snapshot(config, context, &effective_workspace_id, query.depth)
.await?
}
StreamSnapshotScope::Subtree => {
let root_node_id =
@@ -590,8 +689,8 @@ pub async fn load_stream_snapshot(
#[cfg(test)]
mod tests {
use super::{
resolve_stream_change, resolve_stream_cursor, resolve_stream_scope, StreamChangeKind,
StreamSnapshotQuery, StreamSnapshotScope,
delta_requires_projection_snapshot, resolve_stream_change, resolve_stream_cursor,
resolve_stream_scope, StreamChangeKind, StreamSnapshotQuery, StreamSnapshotScope,
};
use serde_json::json;
@@ -1192,4 +1291,39 @@ mod tests {
assert_eq!(change.kind, StreamChangeKind::Resync);
assert_eq!(change.delta, None);
}
#[test]
fn title_only_delta_does_not_require_projection_snapshot() {
assert!(!delta_requires_projection_snapshot(&json!({
"op": "upsert_document",
"document": {
"id": "page_1",
"title": "新标题"
}
})));
assert!(!delta_requires_projection_snapshot(&json!({
"op": "upsert_documents",
"upsertDocuments": [
{
"id": "page_1",
"title": "新标题"
}
]
})));
}
#[test]
fn structural_delta_requires_projection_snapshot() {
assert!(delta_requires_projection_snapshot(&json!({
"op": "move_document",
"documentId": "page_1",
"parentId": "page_2"
})));
assert!(delta_requires_projection_snapshot(&json!({
"op": "upsert_assets",
"upsertAssets": [
{ "id": "asset_1" }
]
})));
}
}