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)]
54pub struct PostQuery<'a, C> {
55 queryer: Queryer<'a, C>,
56 pub ids: IdFilter<PostId>,
57 pub title: TextFilter,
58 pub source: TextFilter,
59 pub updated: DateFilter,
60 pub published: DateFilter,
61 pub platforms: IdFilter<PlatformId>,
62 pub tags: RelationshipsFilter<TagId>,
63 pub authors: RelationshipsFilter<AuthorId>,
64 pub collections: RelationshipsFilter<CollectionId>,
65}
66
67impl<'a, C: PostArchiverConnection> PostQuery<'a, C> {
70 pub fn new(manager: &'a PostArchiverManager<C>) -> Self {
71 PostQuery {
72 queryer: Queryer::new(manager),
73 ids: IdFilter::new("id"),
74 title: TextFilter::new("title"),
75 source: TextFilter::new("source"),
76 updated: DateFilter::new("updated"),
77 published: DateFilter::new("published"),
78 platforms: IdFilter::new("platform"),
79 tags: RelationshipsFilter::new("post_tags", "tag"),
80 authors: RelationshipsFilter::new("author_posts", "author"),
81 collections: RelationshipsFilter::new("collection_posts", "collection"),
82 }
83 }
84}
85
86impl<C: PostArchiverConnection> BaseFilter for PostQuery<'_, C> {
89 type Based = Post;
90
91 fn update_sql<T: FromQuery<Based = Self::Based>>(&self, mut sql: RawSql<T>) -> RawSql<T> {
92 sql = self.ids.build_sql(sql);
93 sql = self.title.build_sql(sql);
94 sql = self.source.build_sql(sql);
95 sql = self.updated.build_sql(sql);
96 sql = self.published.build_sql(sql);
97 sql = self.platforms.build_sql(sql);
98 sql = self.authors.build_sql(sql);
99 sql = self.tags.build_sql(sql);
100 sql = self.collections.build_sql(sql);
101
102 sql
103 }
104
105 fn queryer(&self) -> &Queryer<'_, impl PostArchiverConnection> {
106 &self.queryer
107 }
108}
109
110impl<C: PostArchiverConnection> Query for PostQuery<'_, C> {
111 type Wrapper<U> = Vec<U>;
112 type Based = Post;
113
114 fn query_with_context<T: FromQuery<Based = Self::Based>>(
115 self,
116 sql: RawSql<T>,
117 ) -> crate::error::Result<Self::Wrapper<T>> {
118 let sql = self.update_sql(sql);
119 let (sql, params) = sql.build_sql();
120 self.queryer.fetch(&sql, params)
121 }
122}
123
124impl<C: PostArchiverConnection> PostArchiverManager<C> {
125 pub fn posts(&self) -> PostQuery<'_, C> {
127 PostQuery::new(self)
128 }
129
130 pub fn get_post(&self, id: PostId) -> crate::error::Result<Option<Post>> {
132 let mut stmt = self
133 .conn()
134 .prepare_cached("SELECT * FROM posts WHERE id = ?")?;
135 Ok(stmt.query_row([id], Post::from_row).optional()?)
136 }
137
138 pub fn find_post(&self, source: &str) -> crate::error::Result<Option<PostId>> {
140 let mut stmt = self
141 .conn()
142 .prepare_cached("SELECT id FROM posts WHERE source = ?")?;
143 Ok(stmt.query_row([source], |row| row.get(0)).optional()?)
144 }
145
146 pub fn find_post_with_updated(
149 &self,
150 source: &str,
151 updated: &DateTime<Utc>,
152 ) -> crate::error::Result<Option<PostId>> {
153 let mut stmt = self
154 .conn()
155 .prepare_cached("SELECT id FROM posts WHERE source = ? AND updated >= ?")?;
156 Ok(stmt
157 .query_row(params![source, updated], |row| row.get(0))
158 .optional()?)
159 }
160}