jax_daemon/database/
bucket_queries.rs1use time::OffsetDateTime;
2use uuid::Uuid;
3
4use crate::database::{types::DCid, Database};
5use common::prelude::Link;
6
7#[derive(Debug, Clone)]
9pub struct BucketInfo {
10 pub id: Uuid,
11 pub name: String,
12 pub link: Link,
13 pub created_at: OffsetDateTime,
14}
15
16#[derive(Debug, Clone)]
18pub struct BucketLogEntry {
19 pub bucket_id: Uuid,
20 pub name: String,
21 pub current_link: Link,
22 pub previous_link: Option<Link>,
23 pub height: u64,
24 pub published: bool,
25 pub created_at: OffsetDateTime,
26}
27
28impl Database {
29 pub async fn get_bucket_info(&self, id: &Uuid) -> Result<Option<BucketInfo>, sqlx::Error> {
31 let id_str = id.to_string();
32 let row = sqlx::query!(
33 r#"
34 SELECT
35 bucket_id as "bucket_id!",
36 name as "name!",
37 current_link as "current_link!: DCid",
38 created_at as "created_at!"
39 FROM bucket_log
40 WHERE bucket_id = $1
41 ORDER BY height DESC
42 LIMIT 1
43 "#,
44 id_str
45 )
46 .fetch_optional(&**self)
47 .await?;
48
49 Ok(row.map(|r| BucketInfo {
50 id: Uuid::parse_str(&r.bucket_id).expect("invalid bucket_id UUID in database"),
51 name: r.name,
52 link: r.current_link.into(),
53 created_at: r.created_at,
54 }))
55 }
56
57 pub async fn list_buckets(
59 &self,
60 prefix: Option<String>,
61 limit: Option<u32>,
62 ) -> Result<Vec<BucketInfo>, sqlx::Error> {
63 let limit_val = limit.unwrap_or(100).min(1000) as i64;
64 let pattern = prefix
65 .map(|p| format!("{}%", p))
66 .unwrap_or_else(|| "%".to_string());
67
68 let rows = sqlx::query!(
69 r#"
70 SELECT
71 bl.bucket_id as "bucket_id!",
72 bl.name as "name!",
73 bl.current_link as "current_link!: DCid",
74 MIN(bl.created_at) as "created_at!"
75 FROM bucket_log bl
76 INNER JOIN (
77 SELECT bucket_id, MAX(height) as max_height
78 FROM bucket_log
79 GROUP BY bucket_id
80 ) latest ON bl.bucket_id = latest.bucket_id AND bl.height = latest.max_height
81 WHERE bl.name LIKE ?1
82 GROUP BY bl.bucket_id, bl.name, bl.current_link
83 ORDER BY created_at DESC
84 LIMIT ?2
85 "#,
86 pattern,
87 limit_val
88 )
89 .fetch_all(&**self)
90 .await?;
91
92 Ok(rows
93 .into_iter()
94 .map(|r| BucketInfo {
95 id: Uuid::parse_str(&r.bucket_id).expect("invalid bucket_id UUID in database"),
96 name: r.name,
97 link: r.current_link.into(),
98 created_at: r.created_at,
99 })
100 .collect())
101 }
102
103 pub async fn get_bucket_logs(
105 &self,
106 bucket_id: &Uuid,
107 page: u32,
108 page_size: u32,
109 ) -> Result<Vec<BucketLogEntry>, sqlx::Error> {
110 let bucket_id_str = bucket_id.to_string();
111 let limit = page_size.min(100) as i64;
112 let offset = (page * page_size) as i64;
113
114 let rows = sqlx::query!(
115 r#"
116 SELECT
117 bucket_id as "bucket_id!",
118 name as "name!",
119 current_link as "current_link!: DCid",
120 previous_link as "previous_link: DCid",
121 height as "height!",
122 published as "published!: bool",
123 created_at as "created_at!"
124 FROM bucket_log
125 WHERE bucket_id = ?1
126 ORDER BY height DESC
127 LIMIT ?2 OFFSET ?3
128 "#,
129 bucket_id_str,
130 limit,
131 offset
132 )
133 .fetch_all(&**self)
134 .await?;
135
136 Ok(rows
137 .into_iter()
138 .map(|r| BucketLogEntry {
139 bucket_id: Uuid::parse_str(&r.bucket_id)
140 .expect("invalid bucket_id UUID in database"),
141 name: r.name,
142 current_link: r.current_link.into(),
143 previous_link: r.previous_link.map(Into::into),
144 height: r.height as u64,
145 published: r.published,
146 created_at: r.created_at,
147 })
148 .collect())
149 }
150
151 pub async fn get_all_bucket_logs(
153 &self,
154 bucket_id: &Uuid,
155 ) -> Result<Vec<BucketLogEntry>, sqlx::Error> {
156 let bucket_id_str = bucket_id.to_string();
157
158 let rows = sqlx::query!(
159 r#"
160 SELECT
161 bucket_id as "bucket_id!",
162 name as "name!",
163 current_link as "current_link!: DCid",
164 previous_link as "previous_link: DCid",
165 height as "height!",
166 published as "published!: bool",
167 created_at as "created_at!"
168 FROM bucket_log
169 WHERE bucket_id = ?1
170 ORDER BY height ASC
171 "#,
172 bucket_id_str
173 )
174 .fetch_all(&**self)
175 .await?;
176
177 Ok(rows
178 .into_iter()
179 .map(|r| BucketLogEntry {
180 bucket_id: Uuid::parse_str(&r.bucket_id)
181 .expect("invalid bucket_id UUID in database"),
182 name: r.name,
183 current_link: r.current_link.into(),
184 previous_link: r.previous_link.map(Into::into),
185 height: r.height as u64,
186 published: r.published,
187 created_at: r.created_at,
188 })
189 .collect())
190 }
191
192 pub async fn get_bucket_log_count(&self, bucket_id: &Uuid) -> Result<i64, sqlx::Error> {
194 let bucket_id_str = bucket_id.to_string();
195
196 let result = sqlx::query!(
197 r#"
198 SELECT COUNT(*) as "count!"
199 FROM bucket_log
200 WHERE bucket_id = ?1
201 "#,
202 bucket_id_str
203 )
204 .fetch_one(&**self)
205 .await?;
206
207 Ok(result.count)
208 }
209}