asurada 0.1.0

Asurada — a memory + cognition daemon that grows with the user. Local-first, BYOK, shared by Devist/Webchemist Core/etc.
// 테이블별 마지막 push/pull 시점 추적.
// Sync 모듈이 어디까지 처리했는지 기록 — 재시작 후 이어서 진행 가능.
//
// Connection / Transaction 어느 쪽에서든 호출 가능하도록 trait object 사용.

use anyhow::Result;
use rusqlite::{params, Connection};

/// rusqlite::Connection 과 Transaction 모두 ToSql 바인딩 + execute/query 가능한 트레잇 같은 것을
/// 직접 정의하기보다, 명시적으로 "Connection 어떤 종류든" 받도록 helper 함수를 분리.

pub fn get_last_pulled(conn: &Connection, table_name: &str) -> Result<Option<String>> {
    let v: Option<String> = conn
        .query_row(
            "SELECT last_pulled_at FROM _sync_state WHERE table_name = ?1",
            params![table_name],
            |row| row.get(0),
        )
        .ok()
        .flatten();
    Ok(v)
}

/// Transaction / Connection 모두 deref 로 동일한 인터페이스 — &Connection 타입으로 받음.
pub fn set_last_pulled<C>(conn: &C, table_name: &str, when: &str) -> Result<()>
where
    C: std::ops::Deref<Target = Connection>,
{
    conn.execute(
        r#"INSERT INTO _sync_state (table_name, last_pulled_at, updated_at)
           VALUES (?1, ?2, ?3)
           ON CONFLICT(table_name) DO UPDATE SET
               last_pulled_at = excluded.last_pulled_at,
               updated_at = excluded.updated_at"#,
        params![table_name, when, chrono::Utc::now().to_rfc3339()],
    )?;
    Ok(())
}

pub fn get_last_pushed(conn: &Connection, table_name: &str) -> Result<Option<String>> {
    let v: Option<String> = conn
        .query_row(
            "SELECT last_pushed_at FROM _sync_state WHERE table_name = ?1",
            params![table_name],
            |row| row.get(0),
        )
        .ok()
        .flatten();
    Ok(v)
}

pub fn set_last_pushed<C>(conn: &C, table_name: &str, when: &str) -> Result<()>
where
    C: std::ops::Deref<Target = Connection>,
{
    conn.execute(
        r#"INSERT INTO _sync_state (table_name, last_pushed_at, updated_at)
           VALUES (?1, ?2, ?3)
           ON CONFLICT(table_name) DO UPDATE SET
               last_pushed_at = excluded.last_pushed_at,
               updated_at = excluded.updated_at"#,
        params![table_name, when, chrono::Utc::now().to_rfc3339()],
    )?;
    Ok(())
}