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