Skip to main content

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}