MCPcopy Create free account
hub / github.com/cortexkit/magic-context / update_memory_content

Function update_memory_content

packages/dashboard/src-tauri/src/db.rs:3315–3388  ·  view source on GitHub ↗
(
    conn: &mut Connection,
    memory_id: i64,
    new_content: &str,
)

Source from the content-addressed store, hash-verified

3313}
3314
3315pub fn update_memory_content(
3316 conn: &mut Connection,
3317 memory_id: i64,
3318 new_content: &str,
3319) -> Result<(), rusqlite::Error> {
3320 // Phase A: resolve the target row before opening a write transaction.
3321 let target = lookup_memory_mutation_target(conn, memory_id)?;
3322 let new_hash = normalize_hash(new_content);
3323
3324 // Phase B: re-check the target row, mutate, clear stale embeddings, and queue once.
3325 let tx = conn.transaction_with_behavior(TransactionBehavior::Immediate)?;
3326 verify_memory_project_path_unchanged(&tx, memory_id, &target.project_path)?;
3327
3328 // Pre-check the UNIQUE(project_path, category, normalized_hash) constraint
3329 // INSIDE the Immediate transaction (no TOCTOU). If editing this memory's
3330 // content makes its hash match another memory in the same project+category,
3331 // a plain UPDATE aborts with a raw `UNIQUE constraint failed: ...` string
3332 // that surfaces verbatim in the dashboard toast. Mirror the TS plugin's
3333 // friendly message so the user knows to merge/archive the duplicate.
3334 // `category = ?2` (not `IS`): SQLite's UNIQUE treats NULL categories as
3335 // distinct (NULLs never collide), and `category = NULL` is never true — so
3336 // a NULL category yields no match here, exactly mirroring the constraint
3337 // the real UPDATE would (not) violate. Avoids a false rejection on NULL.
3338 let collision_id: Option<i64> = tx
3339 .query_row(
3340 "SELECT id FROM memories
3341 WHERE project_path = ?1 AND category = ?2 AND normalized_hash = ?3 AND id != ?4
3342 LIMIT 1",
3343 params![target.project_path, target.category, new_hash, memory_id],
3344 |row| row.get(0),
3345 )
3346 .optional()?;
3347 if let Some(existing_id) = collision_id {
3348 // SqliteFailure(_, Some(msg)) Displays as exactly `msg`, so commands.rs's
3349 // `.to_string()` surfaces this friendly text (not a raw SQLite error)
3350 // in the dashboard toast. rusqlite 0.31 has no ModuleError variant.
3351 return Err(rusqlite::Error::SqliteFailure(
3352 rusqlite::ffi::Error::new(rusqlite::ffi::SQLITE_CONSTRAINT),
3353 Some(format!(
3354 "Memory content already exists as ID {existing_id} in this category; merge or archive the duplicate first."
3355 )),
3356 ));
3357 }
3358
3359 tx.execute(
3360 "UPDATE memories SET content = ?1, normalized_hash = ?2, updated_at = ?3 WHERE id = ?4",
3361 params![new_content, new_hash, now_millis(), memory_id],
3362 )?;
3363 // The classify `shareable` verdict was scored against the OLD content; a
3364 // dashboard content edit invalidates it. Fail closed → private; the dreamer
3365 // re-scores later. Mirrors the plugin's updateMemoryContent. Column-guarded
3366 // for pre-v44 DBs.
3367 if memories_has_classify_columns(&tx) {
3368 tx.execute(
3369 "UPDATE memories SET shareable = 0 WHERE id = ?1",
3370 params![memory_id],
3371 )?;
3372 }

Calls 7

normalize_hashFunction · 0.85
queue_memory_mutationFunction · 0.85
getMethod · 0.80
commitMethod · 0.80