post_archiver/query/
post.rs1use chrono::{DateTime, Utc};
4use rusqlite::{params, OptionalExtension};
5
6use crate::{
7 manager::{PostArchiverConnection, PostArchiverManager},
8 AuthorId, CollectionId, PlatformId, Post, PostId, TagId,
9};
10
11use super::{
12 filter::{DateFilter, IdFilter, RelationshipsFilter, TextFilter},
13 sortable::impl_sortable,
14 BaseFilter, FromQuery, Query, Queryer, RawSql,
15};
16
17impl_sortable!(PostQuery(PostSort) {
18 Id: "id",
19 Updated: "updated",
20 Published: "published",
21 Title: "title"
22});
23
24#[derive(Debug)]
52pub struct PostQuery<'a, C> {
53 queryer: Queryer<'a, C>,
54 pub ids: IdFilter<PostId>,
55 pub title: TextFilter,
56 pub source: TextFilter,
57 pub updated: DateFilter,
58 pub published: DateFilter,
59 pub platforms: IdFilter<PlatformId>,
60 pub tags: RelationshipsFilter<TagId>,
61 pub authors: RelationshipsFilter<AuthorId>,
62 pub collections: RelationshipsFilter<CollectionId>,
63}
64
65impl<'a, C: PostArchiverConnection> PostQuery<'a, C> {
68 pub fn new(manager: &'a PostArchiverManager<C>) -> Self {
69 PostQuery {
70 queryer: Queryer::new(manager),
71 ids: IdFilter::new("id"),
72 title: TextFilter::new("title"),
73 source: TextFilter::new("source"),
74 updated: DateFilter::new("updated"),
75 published: DateFilter::new("published"),
76 platforms: IdFilter::new("platform"),
77 tags: RelationshipsFilter::new("post_tags", "tag"),
78 authors: RelationshipsFilter::new("author_posts", "author"),
79 collections: RelationshipsFilter::new("collection_posts", "collection"),
80 }
81 }
82}
83
84impl<C: PostArchiverConnection> BaseFilter for PostQuery<'_, C> {
87 type Based = Post;
88
89 fn update_sql<T: FromQuery<Based = Self::Based>>(&self, mut sql: RawSql<T>) -> RawSql<T> {
90 sql = self.ids.build_sql(sql);
91 sql = self.title.build_sql(sql);
92 sql = self.source.build_sql(sql);
93 sql = self.updated.build_sql(sql);
94 sql = self.published.build_sql(sql);
95 sql = self.platforms.build_sql(sql);
96 sql = self.authors.build_sql(sql);
97 sql = self.tags.build_sql(sql);
98 sql = self.collections.build_sql(sql);
99
100 sql
101 }
102
103 fn queryer(&self) -> &Queryer<'_, impl PostArchiverConnection> {
104 &self.queryer
105 }
106}
107
108impl<C: PostArchiverConnection> Query for PostQuery<'_, C> {
109 type Wrapper<U> = Vec<U>;
110 type Based = Post;
111
112 fn query_with_context<T: FromQuery<Based = Self::Based>>(
113 self,
114 sql: RawSql<T>,
115 ) -> crate::error::Result<Self::Wrapper<T>> {
116 let sql = self.update_sql(sql);
117 let (sql, params) = sql.build_sql();
118 self.queryer.fetch(&sql, params)
119 }
120}
121
122impl<C: PostArchiverConnection> PostArchiverManager<C> {
123 pub fn posts(&self) -> PostQuery<'_, C> {
125 PostQuery::new(self)
126 }
127
128 pub fn get_post(&self, id: PostId) -> crate::error::Result<Option<Post>> {
130 let mut stmt = self
131 .conn()
132 .prepare_cached("SELECT * FROM posts WHERE id = ?")?;
133 Ok(stmt.query_row([id], Post::from_row).optional()?)
134 }
135
136 pub fn find_post(&self, source: &str) -> crate::error::Result<Option<PostId>> {
138 let mut stmt = self
139 .conn()
140 .prepare_cached("SELECT id FROM posts WHERE source = ?")?;
141 Ok(stmt.query_row([source], |row| row.get(0)).optional()?)
142 }
143
144 pub fn find_post_with_updated(
147 &self,
148 source: &str,
149 updated: &DateTime<Utc>,
150 ) -> crate::error::Result<Option<PostId>> {
151 let mut stmt = self
152 .conn()
153 .prepare_cached("SELECT id FROM posts WHERE source = ? AND updated >= ?")?;
154 Ok(stmt
155 .query_row(params![source, updated], |row| row.get(0))
156 .optional()?)
157 }
158}