summaryrefslogtreecommitdiff
path: root/src/database.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/database.rs')
-rw-r--r--src/database.rs90
1 files changed, 61 insertions, 29 deletions
diff --git a/src/database.rs b/src/database.rs
index 77397a5..d27646b 100644
--- a/src/database.rs
+++ b/src/database.rs
@@ -23,6 +23,14 @@ use std::path::Path;
#[derive(Debug)]
pub struct TagDatabase(Connection);
+/// Tag query with a sense of "state" for pagination.
+#[derive(Debug)]
+pub struct Query<'a> {
+ tags: &'a [&'a str],
+ last_id: Option<i64>,
+ limit: Option<i64>,
+}
+
impl TagDatabase {
/// Instantiate a new `TagDatabase` whose backing database is at `path`.
pub fn new(path: &str) -> Result<Self> {
@@ -137,49 +145,64 @@ impl TagDatabase {
}
/// Return the intersection of the sets of images matching each of `tags`.
- pub fn images_by_tags(&self, tags: &[&str]) -> Result<Vec<Image>> {
- let ids: Vec<i64> = tags
+ pub fn query(&self, q: Query) -> Result<Vec<Image>> {
+ let ids: Vec<i64> = q
+ .tags
.iter()
.filter_map(|tag| self.tag_id(tag).ok())
.collect();
- let mut tags = Vec::from(tags);
+ let mut tags = Vec::from(q.tags);
tags.dedup();
+ // Query contained a tag that's not in the database.
if ids.len() != tags.len() {
return Ok(vec![]);
}
let union = if tags.is_empty() {
- String::from(
- "INNER JOIN mapping
- ON images.id = mapping.image",
- )
+ None
} else {
- (1..ids.len() + 1)
- .zip(ids)
- .map(|pair| {
- let (n, id) = pair;
- format!(
- "INNER JOIN mapping as m{n}
+ Some(
+ (1..ids.len() + 1)
+ .zip(ids)
+ .map(|pair| {
+ let (n, id) = pair;
+ format!(
+ "INNER JOIN mapping as m{n}
ON images.id = m{n}.image
AND {id} = m{n}.tag",
- n = n,
- id = id
- )
- })
- .collect::<Vec<String>>()
- .join("\n")
+ n = n,
+ id = id
+ )
+ })
+ .collect::<Vec<String>>()
+ .join("\n"),
+ )
+ };
+
+ let query = if let (Some(id), Some(n)) = (q.last_id, q.limit) {
+ format!(
+ "SELECT id, blake2, filename, orig_dir
+ FROM images
+ {union}
+ WHERE id > {last_id}
+ GROUP BY id
+ ORDER BY id DESC
+ LIMIT {limit}",
+ last_id = id,
+ union = union.or(Some("".into())).unwrap(),
+ limit = n
+ )
+ } else {
+ format!(
+ "SELECT id, blake2, filename, orig_dir
+ FROM images
+ {union}
+ GROUP BY id
+ ORDER BY id DESC",
+ union = union.or(Some("".into())).unwrap(),
+ )
};
- // WHERE id > {lastId}
- // LIMIT 50
- let query = format!(
- "SELECT id, blake2, filename, orig_dir
- FROM images
- {union}
- GROUP BY id
- ORDER BY id DESC",
- union = union
- );
Ok(self
.0
@@ -204,6 +227,15 @@ impl TagDatabase {
})
.collect())
}
+
+ /// Return the intersection of the sets of images matching each of `tags`.
+ pub fn images_by_tags(&self, tags: &[&str]) -> Result<Vec<Image>> {
+ self.query(Query {
+ tags,
+ last_id: None,
+ limit: None,
+ })
+ }
}
/// The result of an image query in бирка-тян's tag database.