core: notes show their real created and edited times, and desktop search works
CI & Build / Build now, or wait for Android? (push) Canceled after 0s
CI & Build / TypeScript typecheck (push) Canceled after 0s
CI & Build / Python lint (push) Canceled after 0s
CI & Build / Python tests (push) Canceled after 0s
CI & Build / integration (push) Canceled after 0s
CI & Build / Build & push image (push) Canceled after 0s
Android / Build, or is the channel already serving this? (push) Successful in 2s
Desktop (Tauri) / Build, or is the channel already serving this? (push) Successful in 2s
Desktop (Tauri) / Windows installer (cross-compiled) (push) Successful in 4m26s
Desktop (Tauri) / Tauri desktop (Linux) (push) Successful in 7m41s
Desktop (Tauri) / Update manifest (push) Successful in 5s
Android / Kotlin + Rust (APK) (push) Successful in 10m41s
CI & Build / Build now, or wait for Android? (push) Canceled after 0s
CI & Build / TypeScript typecheck (push) Canceled after 0s
CI & Build / Python lint (push) Canceled after 0s
CI & Build / Python tests (push) Canceled after 0s
CI & Build / integration (push) Canceled after 0s
CI & Build / Build & push image (push) Canceled after 0s
Android / Build, or is the channel already serving this? (push) Successful in 2s
Desktop (Tauri) / Build, or is the channel already serving this? (push) Successful in 2s
Desktop (Tauri) / Windows installer (cross-compiled) (push) Successful in 4m26s
Desktop (Tauri) / Tauri desktop (Linux) (push) Successful in 7m41s
Desktop (Tauri) / Update manifest (push) Successful in 5s
Android / Kotlin + Rust (APK) (push) Successful in 10m41s
Both bugs were caught red by the tests in732fd7a(run 8418: 5 failed, 147 passed) before this fix. - load_note reads columns by NAME. Dropping `color` (fa89da1) shifted every column after it and the two timestamps were missed, so created_at showed the last edit and updated_at showed the trash time — null on any live note. Only the read was wrong; nothing stored is, so no data needs repairing. - The board's text facet binds its pattern once for its one placeholder. It pushed it twice after the title column went (95aa10c), and rusqlite refused every query with InvalidParameterCount — every desktop search failed. Android searches through store::search and was never affected. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+23
-20
@@ -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))?;
|
||||
|
||||
Reference in New Issue
Block a user