ceylon_next/memory/
migration.rs

1//! Memory migration utilities for transferring data between backends.
2//!
3//! This module provides functions to migrate, export, and import memory entries
4//! between different storage backends.
5
6use super::{Memory, MemoryEntry};
7use std::fs;
8use std::path::PathBuf;
9
10/// Migrates memory entries from one backend to another.
11///
12/// # Arguments
13///
14/// * `source` - The source memory backend to read from
15/// * `target` - The target memory backend to write to
16/// * `agent_id` - Agent ID to migrate memories for
17///
18/// # Returns
19///
20/// The number of entries migrated, or an error message
21///
22/// # Examples
23///
24/// ```rust,no_run
25/// use ceylon_next::memory::{InMemoryStore, FileStore, StorageFormat, migrate_memory};
26/// use std::sync::Arc;
27///
28/// #[tokio::main]
29/// async fn main() {
30///     let source = Arc::new(InMemoryStore::new());
31///     let target = Arc::new(
32///         FileStore::new("backup.json", StorageFormat::Json).await.unwrap()
33///     );
34///
35///     // Migrate specific agent's memories
36///     let count = migrate_memory(&*source, &*target, "agent-123").await.unwrap();
37///     println!("Migrated {} entries for agent-123", count);
38/// }
39/// ```
40pub async fn migrate_memory(
41    source: &dyn Memory,
42    target: &dyn Memory,
43    agent_id: &str,
44) -> Result<usize, String> {
45    let entries = source.get_agent_history(agent_id).await?;
46
47    let mut count = 0;
48    for entry in entries {
49        target.store(entry).await?;
50        count += 1;
51    }
52
53    Ok(count)
54}
55
56/// Exports all memory entries to a JSON file.
57///
58/// # Arguments
59///
60/// * `source` - The source memory backend to read from
61/// * `agent_id` - The agent ID whose memories to export
62/// * `file_path` - Path to the output JSON file
63///
64/// # Examples
65///
66/// ```rust,no_run
67/// use ceylon_next::memory::{InMemoryStore, export_to_json};
68/// use std::sync::Arc;
69///
70/// #[tokio::main]
71/// async fn main() {
72///     let memory = Arc::new(InMemoryStore::new());
73///     export_to_json(&*memory, "agent-123", "backup.json").await.unwrap();
74/// }
75/// ```
76pub async fn export_to_json<P: Into<PathBuf>>(
77    source: &dyn Memory,
78    agent_id: &str,
79    file_path: P,
80) -> Result<usize, String> {
81    let entries = source.get_agent_history(agent_id).await?;
82    let count = entries.len();
83
84    let json = serde_json::to_string_pretty(&entries)
85        .map_err(|e| format!("Failed to serialize to JSON: {}", e))?;
86
87    fs::write(file_path.into(), json)
88        .map_err(|e| format!("Failed to write file: {}", e))?;
89
90    Ok(count)
91}
92
93/// Imports memory entries from a JSON file.
94///
95/// # Arguments
96///
97/// * `target` - The target memory backend to write to
98/// * `file_path` - Path to the input JSON file
99///
100/// # Examples
101///
102/// ```rust,no_run
103/// use ceylon_next::memory::{SqliteStore, import_from_json};
104/// use std::sync::Arc;
105///
106/// #[tokio::main]
107/// async fn main() {
108///     let memory = Arc::new(SqliteStore::new("memory.db").await.unwrap());
109///     let count = import_from_json(&*memory, "backup.json").await.unwrap();
110///     println!("Imported {} entries", count);
111/// }
112/// ```
113pub async fn import_from_json<P: Into<PathBuf>>(
114    target: &dyn Memory,
115    file_path: P,
116) -> Result<usize, String> {
117    let json = fs::read_to_string(file_path.into())
118        .map_err(|e| format!("Failed to read file: {}", e))?;
119
120    let entries: Vec<MemoryEntry> = serde_json::from_str(&json)
121        .map_err(|e| format!("Failed to deserialize JSON: {}", e))?;
122
123    let mut count = 0;
124    for entry in entries {
125        target.store(entry).await?;
126        count += 1;
127    }
128
129    Ok(count)
130}
131
132/// Exports all memory entries to a MessagePack file.
133///
134/// # Arguments
135///
136/// * `source` - The source memory backend to read from
137/// * `agent_id` - The agent ID whose memories to export
138/// * `file_path` - Path to the output MessagePack file
139///
140/// # Examples
141///
142/// ```rust,no_run
143/// use ceylon_next::memory::{InMemoryStore, export_to_msgpack};
144/// use std::sync::Arc;
145///
146/// #[tokio::main]
147/// async fn main() {
148///     let memory = Arc::new(InMemoryStore::new());
149///     export_to_msgpack(&*memory, "agent-123", "backup.msgpack").await.unwrap();
150/// }
151/// ```
152pub async fn export_to_msgpack<P: Into<PathBuf>>(
153    source: &dyn Memory,
154    agent_id: &str,
155    file_path: P,
156) -> Result<usize, String> {
157    let entries = source.get_agent_history(agent_id).await?;
158    let count = entries.len();
159
160    let msgpack = rmp_serde::to_vec(&entries)
161        .map_err(|e| format!("Failed to serialize to MessagePack: {}", e))?;
162
163    fs::write(file_path.into(), msgpack)
164        .map_err(|e| format!("Failed to write file: {}", e))?;
165
166    Ok(count)
167}
168
169/// Imports memory entries from a MessagePack file.
170///
171/// # Arguments
172///
173/// * `target` - The target memory backend to write to
174/// * `file_path` - Path to the input MessagePack file
175///
176/// # Examples
177///
178/// ```rust,no_run
179/// use ceylon_next::memory::{SqliteStore, import_from_msgpack};
180/// use std::sync::Arc;
181///
182/// #[tokio::main]
183/// async fn main() {
184///     let memory = Arc::new(SqliteStore::new("memory.db").await.unwrap());
185///     let count = import_from_msgpack(&*memory, "backup.msgpack").await.unwrap();
186///     println!("Imported {} entries", count);
187/// }
188/// ```
189pub async fn import_from_msgpack<P: Into<PathBuf>>(
190    target: &dyn Memory,
191    file_path: P,
192) -> Result<usize, String> {
193    let msgpack = fs::read(file_path.into())
194        .map_err(|e| format!("Failed to read file: {}", e))?;
195
196    let entries: Vec<MemoryEntry> = rmp_serde::from_slice(&msgpack)
197        .map_err(|e| format!("Failed to deserialize MessagePack: {}", e))?;
198
199    let mut count = 0;
200    for entry in entries {
201        target.store(entry).await?;
202        count += 1;
203    }
204
205    Ok(count)
206}