kmp_embedded/migration.rs
1//! Store migration, composed.
2//!
3//! The machinery lives in the storage adapter; what belongs here is the one
4//! decision it deliberately does not make — how a context event becomes
5//! projection mutations. That derivation is the application's, and injecting
6//! it here is what keeps the adapter free of the layer above it and the MCP
7//! binary free of the layer below.
8
9use std::path::Path;
10
11use kmp_adapter_embedded::{EmbeddedKernelStore, StoreMigrationReceipt};
12use kmp_domain::PortError;
13
14/// Migrates `source_dir` into `destination_dir`, returning what was moved.
15///
16/// The source is never opened for writing and its bytes are verified
17/// unchanged when the migration finishes; the destination must not already
18/// hold a store.
19pub async fn migrate_data_dir(
20 source_dir: &Path,
21 destination_dir: &Path,
22) -> Result<StoreMigrationReceipt, PortError> {
23 let (_store, receipt) = EmbeddedKernelStore::migrate_data_dir(
24 source_dir,
25 destination_dir,
26 kmp_application::projection_mutations_for_context_event,
27 )
28 .await?;
29 Ok(receipt)
30}
31
32/// Migrate once, reopen afterwards. Safe on every start: a destination that
33/// already holds a store is opened as it is, and the returned receipt says
34/// whether this call was the one that migrated it.
35pub async fn open_or_migrate_data_dir(
36 source_dir: &Path,
37 destination_dir: &Path,
38) -> Result<Option<StoreMigrationReceipt>, PortError> {
39 let (_store, receipt) = EmbeddedKernelStore::open_or_migrate_data_dir(
40 source_dir,
41 destination_dir,
42 kmp_application::projection_mutations_for_context_event,
43 )
44 .await?;
45 Ok(receipt)
46}