]> Untitled Git - lemmy.git/blob - lemmy_db/src/lib.rs
remove timing files added by accident
[lemmy.git] / lemmy_db / src / lib.rs
1 #[macro_use]
2 extern crate diesel;
3 #[macro_use]
4 extern crate strum_macros;
5 #[macro_use]
6 extern crate lazy_static;
7
8 use diesel::{result::Error, *};
9 use regex::Regex;
10 use serde::{Deserialize, Serialize};
11 use std::{env, env::VarError};
12
13 pub mod aggregates;
14 pub mod source;
15 pub mod views;
16
17 pub type DbPool = diesel::r2d2::Pool<diesel::r2d2::ConnectionManager<diesel::PgConnection>>;
18
19 pub trait Crud<T> {
20   fn create(conn: &PgConnection, form: &T) -> Result<Self, Error>
21   where
22     Self: Sized;
23   fn read(conn: &PgConnection, id: i32) -> Result<Self, Error>
24   where
25     Self: Sized;
26   fn update(conn: &PgConnection, id: i32, form: &T) -> Result<Self, Error>
27   where
28     Self: Sized;
29   fn delete(_conn: &PgConnection, _id: i32) -> Result<usize, Error>
30   where
31     Self: Sized,
32   {
33     unimplemented!()
34   }
35 }
36
37 pub trait Followable<T> {
38   fn follow(conn: &PgConnection, form: &T) -> Result<Self, Error>
39   where
40     Self: Sized;
41   fn follow_accepted(conn: &PgConnection, community_id: i32, user_id: i32) -> Result<Self, Error>
42   where
43     Self: Sized;
44   fn unfollow(conn: &PgConnection, form: &T) -> Result<usize, Error>
45   where
46     Self: Sized;
47   fn has_local_followers(conn: &PgConnection, community_id: i32) -> Result<bool, Error>;
48 }
49
50 pub trait Joinable<T> {
51   fn join(conn: &PgConnection, form: &T) -> Result<Self, Error>
52   where
53     Self: Sized;
54   fn leave(conn: &PgConnection, form: &T) -> Result<usize, Error>
55   where
56     Self: Sized;
57 }
58
59 pub trait Likeable<T> {
60   fn like(conn: &PgConnection, form: &T) -> Result<Self, Error>
61   where
62     Self: Sized;
63   fn remove(conn: &PgConnection, user_id: i32, item_id: i32) -> Result<usize, Error>
64   where
65     Self: Sized;
66 }
67
68 pub trait Bannable<T> {
69   fn ban(conn: &PgConnection, form: &T) -> Result<Self, Error>
70   where
71     Self: Sized;
72   fn unban(conn: &PgConnection, form: &T) -> Result<usize, Error>
73   where
74     Self: Sized;
75 }
76
77 pub trait Saveable<T> {
78   fn save(conn: &PgConnection, form: &T) -> Result<Self, Error>
79   where
80     Self: Sized;
81   fn unsave(conn: &PgConnection, form: &T) -> Result<usize, Error>
82   where
83     Self: Sized;
84 }
85
86 pub trait Readable<T> {
87   fn mark_as_read(conn: &PgConnection, form: &T) -> Result<Self, Error>
88   where
89     Self: Sized;
90   fn mark_as_unread(conn: &PgConnection, form: &T) -> Result<usize, Error>
91   where
92     Self: Sized;
93 }
94
95 pub trait Reportable<T> {
96   fn report(conn: &PgConnection, form: &T) -> Result<Self, Error>
97   where
98     Self: Sized;
99   fn resolve(conn: &PgConnection, report_id: i32, resolver_id: i32) -> Result<usize, Error>
100   where
101     Self: Sized;
102   fn unresolve(conn: &PgConnection, report_id: i32, resolver_id: i32) -> Result<usize, Error>
103   where
104     Self: Sized;
105 }
106
107 pub trait ApubObject<T> {
108   fn read_from_apub_id(conn: &PgConnection, object_id: &str) -> Result<Self, Error>
109   where
110     Self: Sized;
111   fn upsert(conn: &PgConnection, user_form: &T) -> Result<Self, Error>
112   where
113     Self: Sized;
114 }
115
116 pub trait MaybeOptional<T> {
117   fn get_optional(self) -> Option<T>;
118 }
119
120 impl<T> MaybeOptional<T> for T {
121   fn get_optional(self) -> Option<T> {
122     Some(self)
123   }
124 }
125
126 impl<T> MaybeOptional<T> for Option<T> {
127   fn get_optional(self) -> Option<T> {
128     self
129   }
130 }
131
132 pub(crate) trait ToSafe {
133   type SafeColumns;
134   fn safe_columns_tuple() -> Self::SafeColumns;
135 }
136
137 pub fn get_database_url_from_env() -> Result<String, VarError> {
138   env::var("LEMMY_DATABASE_URL")
139 }
140
141 #[derive(EnumString, ToString, Debug, Serialize, Deserialize)]
142 pub enum SortType {
143   Active,
144   Hot,
145   New,
146   TopDay,
147   TopWeek,
148   TopMonth,
149   TopYear,
150   TopAll,
151 }
152
153 #[derive(EnumString, ToString, Debug, Serialize, Deserialize, Clone)]
154 pub enum ListingType {
155   All,
156   Local,
157   Subscribed,
158   Community,
159 }
160
161 #[derive(EnumString, ToString, Debug, Serialize, Deserialize)]
162 pub enum SearchType {
163   All,
164   Comments,
165   Posts,
166   Communities,
167   Users,
168   Url,
169 }
170
171 pub fn fuzzy_search(q: &str) -> String {
172   let replaced = q.replace(" ", "%");
173   format!("%{}%", replaced)
174 }
175
176 pub fn limit_and_offset(page: Option<i64>, limit: Option<i64>) -> (i64, i64) {
177   let page = page.unwrap_or(1);
178   let limit = limit.unwrap_or(10);
179   let offset = limit * (page - 1);
180   (limit, offset)
181 }
182
183 pub fn is_email_regex(test: &str) -> bool {
184   EMAIL_REGEX.is_match(test)
185 }
186
187 pub fn diesel_option_overwrite(opt: &Option<String>) -> Option<Option<String>> {
188   match opt {
189     // An empty string is an erase
190     Some(unwrapped) => {
191       if !unwrapped.eq("") {
192         Some(Some(unwrapped.to_owned()))
193       } else {
194         Some(None)
195       }
196     }
197     None => None,
198   }
199 }
200
201 lazy_static! {
202   static ref EMAIL_REGEX: Regex =
203     Regex::new(r"^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$").unwrap();
204 }
205
206 pub(crate) mod functions {
207   use diesel::sql_types::*;
208
209   sql_function! {
210     fn hot_rank(score: BigInt, time: Timestamp) -> Integer;
211   }
212 }
213
214 #[cfg(test)]
215 mod tests {
216   use super::fuzzy_search;
217   use crate::{get_database_url_from_env, is_email_regex};
218   use diesel::{Connection, PgConnection};
219
220   pub fn establish_unpooled_connection() -> PgConnection {
221     let db_url = match get_database_url_from_env() {
222       Ok(url) => url,
223       Err(e) => panic!(
224         "Failed to read database URL from env var LEMMY_DATABASE_URL: {}",
225         e
226       ),
227     };
228     PgConnection::establish(&db_url).unwrap_or_else(|_| panic!("Error connecting to {}", db_url))
229   }
230
231   #[test]
232   fn test_fuzzy_search() {
233     let test = "This is a fuzzy search";
234     assert_eq!(fuzzy_search(test), "%This%is%a%fuzzy%search%".to_string());
235   }
236
237   #[test]
238   fn test_email() {
239     assert!(is_email_regex("gush@gmail.com"));
240     assert!(!is_email_regex("nada_neutho"));
241   }
242 }