use rusqlite::{Connection, params};
use crate::TalonError;
use crate::indexing::migrations::bump_db_version;
use super::{NoteUpsertResult, UpsertNoteParams};
fn random_docid() -> String {
use std::sync::atomic::{AtomicU64, Ordering};
use std::time::{SystemTime, UNIX_EPOCH};
static SEQ: AtomicU64 = AtomicU64::new(0);
let seq = SEQ.fetch_add(1, Ordering::Relaxed);
let nanos = SystemTime::now()
.duration_since(UNIX_EPOCH)
.map_or(0, |d| d.as_nanos());
format!("doc-{nanos:x}-{seq:x}")
}
pub fn upsert_note(
conn: &Connection,
params: &UpsertNoteParams<'_>,
) -> Result<NoteUpsertResult, TalonError> {
let aliases_json =
serde_json::to_string(params.aliases).map_err(|err| TalonError::Internal {
message: format!(
"serializing aliases for {} failed: {err}",
params.vault_path
),
})?;
let tags_json = serde_json::to_string(params.tags).map_err(|err| TalonError::Internal {
message: format!("serializing tags for {} failed: {err}", params.vault_path),
})?;
let frontmatter_json =
serde_json::to_string(params.frontmatter).map_err(|err| TalonError::Internal {
message: format!(
"serializing frontmatter for {} failed: {err}",
params.vault_path
),
})?;
let existing: Option<i64> = conn
.query_row(
"SELECT id FROM notes WHERE vault_path = ?",
[params.vault_path],
|row| row.get(0),
)
.ok();
if let Some(note_id) = existing {
conn.execute(
"UPDATE notes SET
title = ?, tags = ?, aliases = ?, content = ?, frontmatter = ?,
mtime_ms = ?, size_bytes = ?, hash = ?, active = 1, scope = ?
WHERE vault_path = ?",
params![
params.title,
tags_json,
aliases_json,
params.content,
frontmatter_json,
params.mtime_ms,
params.size_bytes,
params.source_hash.as_str(),
params.scope,
params.vault_path,
],
)
.map_err(|source| TalonError::Sqlite {
context: "update note",
source,
})?;
bump_db_version(conn)?;
return Ok(NoteUpsertResult {
note_id,
is_new: false,
});
}
let docid = random_docid();
conn.execute(
"INSERT INTO notes
(vault_path, title, tags, aliases, content, frontmatter,
mtime_ms, size_bytes, hash, docid, active, scope)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?)",
params![
params.vault_path,
params.title,
tags_json,
aliases_json,
params.content,
frontmatter_json,
params.mtime_ms,
params.size_bytes,
params.source_hash.as_str(),
docid,
params.scope,
],
)
.map_err(|source| TalonError::Sqlite {
context: "insert note",
source,
})?;
let note_id: i64 = conn
.query_row(
"SELECT id FROM notes WHERE vault_path = ?",
[params.vault_path],
|row| row.get(0),
)
.map_err(|source| TalonError::Sqlite {
context: "fetch newly inserted note id",
source,
})?;
bump_db_version(conn)?;
Ok(NoteUpsertResult {
note_id,
is_new: true,
})
}