AGPL-3.0-only, a source link in the app, and everything on dev since #5 #6

Merged
bvandeusen merged 214 commits from dev into main 2026-10-21 21:40:00 -04:00
Showing only changes of commit be200641cd - Show all commits
+23 -20
View File
@@ -144,25 +144,28 @@ fn load_note(conn: &Connection, id: &str) -> rusqlite::Result<Note> {
"SELECT id, body, position, pinned, archived, trashed, remind_at, recurrence, created_at, updated_at, trashed_at
FROM notes WHERE id = ?1",
[id],
// By NAME, not by position. Dropping `color` shifted every column after it
// and the two timestamps were missed (fa89da1): created_at read updated_at
// and updated_at read trashed_at, with nothing failing. A name either
// resolves or errors.
|r| {
let body: String = r.get(1)?;
Ok(Note {
id: r.get(0)?,
display_title: String::new(), // filled below — it may need a query
body,
position: r.get(2)?,
pinned: r.get(3)?,
archived: r.get(4)?,
trashed: r.get(5)?,
deleted_at: r.get(10)?,
remind_at: r.get(6)?,
recurrence: r.get(7)?,
id: r.get("id")?,
display_title: String::new(), // derived below, from the body
body: r.get("body")?,
position: r.get("position")?,
pinned: r.get("pinned")?,
archived: r.get("archived")?,
trashed: r.get("trashed")?,
deleted_at: r.get("trashed_at")?,
remind_at: r.get("remind_at")?,
recurrence: r.get("recurrence")?,
labels: Vec::new(),
items: Vec::new(),
attachments: Vec::new(),
previews: Vec::new(),
created_at: r.get(9)?,
updated_at: r.get(10)?,
created_at: r.get("created_at")?,
updated_at: r.get("updated_at")?,
})
},
)?;
@@ -321,10 +324,11 @@ pub fn list_notes(conn: &Connection, q: &ListQuery) -> rusqlite::Result<Vec<Note
if let Some(f) = &q.facets {
if let Some(text) = f.q.as_deref().filter(|s| !s.is_empty()) {
// One placeholder, one bind. This pushed the pattern twice after the
// title column went (95aa10c), and rusqlite refuses a count mismatch,
// so every desktop search failed.
sql.push_str(" AND body LIKE ? ESCAPE '\\'");
let pat = format!("%{}%", escape_like(text));
binds.push(pat.clone());
binds.push(pat);
binds.push(format!("%{}%", escape_like(text)));
}
if f.has_reminder == Some(true) {
sql.push_str(" AND remind_at IS NOT NULL");
@@ -371,10 +375,9 @@ pub fn reminders(conn: &Connection) -> rusqlite::Result<Vec<Note>> {
}
pub fn titles(conn: &Connection) -> rusqlite::Result<Vec<TitleEntry>> {
// Names come from `load_note` rather than from a bare row, because a note whose
// body is empty is named by its first checklist item — which a row here doesn't
// have. The command palette reads this; correctness beats one query per note at
// personal scale.
// Names come from `load_note` so the palette and the card can never disagree
// about what a note is called. The command palette reads this; correctness
// beats one query per note at personal scale.
let ids: Vec<String> = {
let mut stmt = conn.prepare("SELECT id FROM notes WHERE trashed = 0")?;
let rows = stmt.query_map([], |r| r.get(0))?;