Skip to main content

client_core/store/
prefix.rs

1use super::models::{MatchInfo, ResolveError};
2use super::Store;
3use rusqlite::params;
4
5pub const MIN_PREFIX: usize = 4;
6const MAX_CANDIDATES: i64 = 6;
7
8pub fn resolve_clip_id(store: &Store, prefix: &str) -> Result<String, ResolveError> {
9    if prefix.len() < MIN_PREFIX {
10        return Err(ResolveError::TooShort);
11    }
12    let pattern = format!("{prefix}%");
13    let matches: Vec<MatchInfo> = store.with_conn(|conn| {
14        let mut stmt = conn.prepare(
15            "SELECT id, source, content_type, created_at, COALESCE(SUBSTR(CAST(content AS TEXT), 1, 40), '') AS preview
16             FROM clips WHERE id LIKE ?1 ORDER BY created_at DESC LIMIT ?2"
17        )?;
18        let rows: Vec<MatchInfo> = stmt
19            .query_map(params![pattern, MAX_CANDIDATES], |r| {
20                Ok(MatchInfo {
21                    id: r.get(0)?,
22                    source: r.get(1)?,
23                    content_type: r.get(2)?,
24                    created_at: r.get(3)?,
25                    preview: r.get(4)?,
26                })
27            })?
28            .filter_map(|r| r.ok())
29            .collect();
30        Ok(rows)
31    })?;
32    match matches.as_slice() {
33        [] => Err(ResolveError::NotFound),
34        [one] => Ok(one.id.clone()),
35        _many => Err(ResolveError::Ambiguous {
36            candidates: matches,
37        }),
38    }
39}
40
41pub fn resolve_device_id(store: &Store, prefix: &str) -> Result<String, ResolveError> {
42    if prefix.len() < MIN_PREFIX {
43        return Err(ResolveError::TooShort);
44    }
45    let pattern = format!("{prefix}%");
46    let mut matches: Vec<MatchInfo> = store.with_conn(|conn| {
47        let mut stmt = conn.prepare(
48            "SELECT id, hostname AS source, '' AS content_type, COALESCE(last_push_at, 0), COALESCE(nickname, hostname)
49             FROM devices WHERE id LIKE ?1 LIMIT ?2"
50        )?;
51        let rows: Vec<MatchInfo> = stmt
52            .query_map(params![pattern, MAX_CANDIDATES], |r| {
53                Ok(MatchInfo {
54                    id: r.get(0)?,
55                    source: r.get(1)?,
56                    content_type: r.get(2)?,
57                    created_at: r.get(3)?,
58                    preview: r.get(4)?,
59                })
60            })?
61            .filter_map(|r| r.ok())
62            .collect();
63        Ok(rows)
64    })?;
65    match matches.len() {
66        0 => Err(ResolveError::NotFound),
67        1 => Ok(matches.remove(0).id),
68        _ => Err(ResolveError::Ambiguous {
69            candidates: matches,
70        }),
71    }
72}