use loonfs_api::{ChangeSeq, ContentRef, DisplayName, InodeId, NameKey, RevisionNo};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub(crate) struct PlannedOp {
pub(crate) preconditions: Vec<CommitPrecondition>,
pub(crate) op: CommitOp,
}
impl PlannedOp {
#[cfg(test)]
pub(crate) fn unchecked(op: CommitOp) -> Self {
Self {
preconditions: Vec::new(),
op,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub(crate) enum CommitOp {
CreateDirectory {
parent_inode_id: InodeId,
display_name: DisplayName,
},
CreateFile {
parent_inode_id: InodeId,
display_name: DisplayName,
content_ref: ContentRef,
},
ReplaceFile {
inode_id: InodeId,
base_revision_no: RevisionNo,
content_ref: ContentRef,
},
RestoreRevision {
inode_id: InodeId,
source_revision_no: RevisionNo,
base_revision_no: RevisionNo,
},
DeleteFile {
inode_id: InodeId,
},
Rename {
inode_id: InodeId,
new_parent_inode_id: InodeId,
new_display_name: DisplayName,
},
DeleteSubtree {
root_inode_id: InodeId,
},
Undelete {
inode_id: InodeId,
deleted_at_seq: ChangeSeq,
parent_inode_id: InodeId,
display_name: DisplayName,
},
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "kind", rename_all = "snake_case")]
pub(crate) enum CommitPrecondition {
InodeRevisionIs {
inode_id: InodeId,
revision_no: RevisionNo,
},
AncestorsNotSubtreeDeleted {
inode_id: InodeId,
},
ChildNameAbsent {
parent_inode_id: InodeId,
name_key: NameKey,
},
BindingIs {
parent_inode_id: InodeId,
name_key: NameKey,
child_inode_id: InodeId,
bind_seq: ChangeSeq,
bind_delta_index: u32,
},
DirectoryEmpty {
inode_id: InodeId,
},
}
#[cfg(test)]
mod tests {
use super::{CommitOp, CommitPrecondition};
use loonfs_api::{InodeId, NameKey};
#[test]
fn commit_precondition_name_key_serializes_as_plain_string() {
let precondition = CommitPrecondition::ChildNameAbsent {
parent_inode_id: InodeId(1),
name_key: NameKey::parse("report.txt").expect("valid name key"),
};
assert_eq!(
serde_json::to_string(&precondition).expect("serialize precondition"),
r#"{"kind":"child_name_absent","parent_inode_id":1,"name_key":"report.txt"}"#
);
}
#[test]
fn commit_precondition_rejects_invalid_name_key() {
let encoded = r#"{
"kind":"child_name_absent",
"parent_inode_id":1,
"name_key":"invalid/name"
}"#;
assert!(serde_json::from_str::<CommitPrecondition>(encoded).is_err());
}
#[test]
fn commit_create_directory_uses_directory_wire_name() {
let op = CommitOp::CreateDirectory {
parent_inode_id: InodeId(1),
display_name: loonfs_api::DisplayName::parse("docs").expect("valid display name"),
};
assert_eq!(
serde_json::to_value(&op).expect("create directory op json"),
serde_json::json!({
"kind": "create_directory",
"parent_inode_id": 1,
"display_name": "docs"
})
);
}
}