claw_branch/commit/cherry.rs
1//! Cherry-pick selection models for selective branch promotion.
2
3use serde::{Deserialize, Serialize};
4use uuid::Uuid;
5
6use crate::types::EntityType;
7
8/// Selects a subset of entities (and optionally fields) from a branch to promote.
9///
10/// # Example
11/// ```rust,ignore
12/// let pick = CherryPick::specific_entities(src, tgt, EntityType::MemoryRecord, vec!["id1".to_string()]);
13/// ```
14#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
15pub struct CherryPick {
16 /// The branch from which entities are sourced.
17 pub source_branch_id: Uuid,
18 /// The branch into which the entities are written.
19 pub target_branch_id: Uuid,
20 /// Ordered list of entity selections to process.
21 pub entity_selections: Vec<EntitySelection>,
22 /// Optional human-readable commit message.
23 pub message: Option<String>,
24}
25
26/// Describes which entities (and which fields) to promote for one entity type.
27#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
28pub struct EntitySelection {
29 /// The entity table to read from.
30 pub entity_type: EntityType,
31 /// The entity identifiers to cherry-pick. An empty vec means *all* entities of this type.
32 pub entity_ids: Vec<String>,
33 /// Restrict promotion to these fields only. `None` means all fields.
34 pub fields: Option<Vec<String>>,
35}
36
37impl CherryPick {
38 /// Promotes every entity of `entity_type` from `source` to `target`.
39 ///
40 /// # Example
41 /// ```rust,ignore
42 /// let pick = CherryPick::all_of_type(src_id, tgt_id, EntityType::MemoryRecord);
43 /// ```
44 pub fn all_of_type(source: Uuid, target: Uuid, entity_type: EntityType) -> Self {
45 Self {
46 source_branch_id: source,
47 target_branch_id: target,
48 entity_selections: vec![EntitySelection {
49 entity_type,
50 entity_ids: Vec::new(),
51 fields: None,
52 }],
53 message: None,
54 }
55 }
56
57 /// Promotes specific entities of `entity_type` from `source` to `target`.
58 ///
59 /// # Example
60 /// ```rust,ignore
61 /// let pick = CherryPick::specific_entities(src_id, tgt_id, EntityType::MemoryRecord, ids);
62 /// ```
63 pub fn specific_entities(
64 source: Uuid,
65 target: Uuid,
66 entity_type: EntityType,
67 ids: Vec<String>,
68 ) -> Self {
69 Self {
70 source_branch_id: source,
71 target_branch_id: target,
72 entity_selections: vec![EntitySelection {
73 entity_type,
74 entity_ids: ids,
75 fields: None,
76 }],
77 message: None,
78 }
79 }
80
81 /// Restricts the last added selection to only the specified field names.
82 ///
83 /// Useful for chaining with [`specific_entities`](Self::specific_entities).
84 pub fn specific_fields(mut self, fields: Vec<String>) -> Self {
85 if let Some(sel) = self.entity_selections.last_mut() {
86 sel.fields = Some(fields);
87 }
88 self
89 }
90
91 /// Attaches a commit message to the cherry-pick.
92 pub fn with_message(mut self, message: impl Into<String>) -> Self {
93 self.message = Some(message.into());
94 self
95 }
96}