feat: added device models
							parent
							
								
									1f4b0c35c5
								
							
						
					
					
						commit
						993e58babf
					
				|  | @ -0,0 +1 @@ | ||||||
|  | drop table devices; | ||||||
|  | @ -0,0 +1,13 @@ | ||||||
|  | create table devices ( | ||||||
|  |     id integer primary key not null, | ||||||
|  | 
 | ||||||
|  |     device_id text not null, | ||||||
|  |     user_id bigint not null | ||||||
|  |         references users (id) | ||||||
|  |         on delete cascade, | ||||||
|  | 
 | ||||||
|  |     caption text not null, | ||||||
|  |     type text not null, | ||||||
|  | 
 | ||||||
|  |     unique (user_id, device_id) | ||||||
|  | ); | ||||||
|  | @ -1,6 +1,7 @@ | ||||||
| pub mod models; | pub mod models; | ||||||
| mod schema; | mod schema; | ||||||
| 
 | 
 | ||||||
|  | pub use models::device::{Device, NewDevice}; | ||||||
| pub use models::session::Session; | pub use models::session::Session; | ||||||
| pub use models::user::{NewUser, User}; | pub use models::user::{NewUser, User}; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -0,0 +1,115 @@ | ||||||
|  | use std::{fmt, str::FromStr}; | ||||||
|  | 
 | ||||||
|  | use diesel::{ | ||||||
|  |     deserialize::{FromSql, FromSqlRow}, | ||||||
|  |     expression::AsExpression, | ||||||
|  |     prelude::*, | ||||||
|  |     serialize::ToSql, | ||||||
|  |     sql_types::Text, | ||||||
|  |     sqlite::{Sqlite, SqliteValue}, | ||||||
|  | }; | ||||||
|  | use serde::{Deserialize, Serialize}; | ||||||
|  | 
 | ||||||
|  | use crate::db::{schema::*, DbPool, DbResult}; | ||||||
|  | 
 | ||||||
|  | #[derive(Serialize, Deserialize, Clone, Queryable, Selectable)] | ||||||
|  | #[diesel(table_name = devices)] | ||||||
|  | #[diesel(check_for_backend(diesel::sqlite::Sqlite))] | ||||||
|  | pub struct Device { | ||||||
|  |     id: i64, | ||||||
|  |     device_id: String, | ||||||
|  |     user_id: i64, | ||||||
|  |     caption: String, | ||||||
|  |     type_: DeviceType, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Deserialize, Insertable)] | ||||||
|  | #[diesel(table_name = devices)] | ||||||
|  | #[diesel(check_for_backend(diesel::sqlite::Sqlite))] | ||||||
|  | pub struct NewDevice { | ||||||
|  |     device_id: String, | ||||||
|  |     user_id: i64, | ||||||
|  |     caption: String, | ||||||
|  |     type_: DeviceType, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Serialize, Deserialize, FromSqlRow, Debug, AsExpression, Clone)] | ||||||
|  | #[diesel(sql_type = Text)] | ||||||
|  | #[serde(rename_all = "lowercase")] | ||||||
|  | pub enum DeviceType { | ||||||
|  |     Desktop, | ||||||
|  |     Laptop, | ||||||
|  |     Mobile, | ||||||
|  |     Server, | ||||||
|  |     Other, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl Device { | ||||||
|  |     pub fn for_user(pool: &DbPool, user_id: i64) -> DbResult<Vec<Self>> { | ||||||
|  |         Ok(devices::dsl::devices | ||||||
|  |             .select(Self::as_select()) | ||||||
|  |             .filter(devices::user_id.eq(user_id)) | ||||||
|  |             .get_results(&mut pool.get()?)?) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl fmt::Display for DeviceType { | ||||||
|  |     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||||||
|  |         write!( | ||||||
|  |             f, | ||||||
|  |             "{}", | ||||||
|  |             match self { | ||||||
|  |                 Self::Desktop => "desktop", | ||||||
|  |                 Self::Laptop => "laptop", | ||||||
|  |                 Self::Mobile => "mobile", | ||||||
|  |                 Self::Server => "server", | ||||||
|  |                 Self::Other => "other", | ||||||
|  |             } | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[derive(Debug)] | ||||||
|  | pub struct DeviceTypeParseErr(String); | ||||||
|  | 
 | ||||||
|  | impl fmt::Display for DeviceTypeParseErr { | ||||||
|  |     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||||||
|  |         write!(f, "invalid device type '{}'", self.0) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl std::error::Error for DeviceTypeParseErr {} | ||||||
|  | 
 | ||||||
|  | impl FromStr for DeviceType { | ||||||
|  |     type Err = DeviceTypeParseErr; | ||||||
|  | 
 | ||||||
|  |     fn from_str(s: &str) -> Result<Self, Self::Err> { | ||||||
|  |         match s { | ||||||
|  |             "desktop" => Ok(Self::Desktop), | ||||||
|  |             "laptop" => Ok(Self::Laptop), | ||||||
|  |             "mobile" => Ok(Self::Mobile), | ||||||
|  |             "server" => Ok(Self::Server), | ||||||
|  |             "other" => Ok(Self::Other), | ||||||
|  |             _ => Err(DeviceTypeParseErr(s.to_string())), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl FromSql<Text, Sqlite> for DeviceType { | ||||||
|  |     fn from_sql(bytes: SqliteValue) -> diesel::deserialize::Result<Self> { | ||||||
|  |         let s = <String as FromSql<Text, Sqlite>>::from_sql(bytes)?; | ||||||
|  | 
 | ||||||
|  |         Ok(s.as_str().parse()?) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl ToSql<Text, Sqlite> for DeviceType { | ||||||
|  |     fn to_sql<'b>( | ||||||
|  |         &'b self, | ||||||
|  |         out: &mut diesel::serialize::Output<'b, '_, Sqlite>, | ||||||
|  |     ) -> diesel::serialize::Result { | ||||||
|  |         out.set_value(self.to_string()); | ||||||
|  | 
 | ||||||
|  |         Ok(diesel::serialize::IsNull::No) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -1,2 +1,3 @@ | ||||||
|  | pub mod device; | ||||||
| pub mod session; | pub mod session; | ||||||
| pub mod user; | pub mod user; | ||||||
|  |  | ||||||
|  | @ -23,15 +23,16 @@ impl Session { | ||||||
|             .get_result(&mut pool.get()?)?) |             .get_result(&mut pool.get()?)?) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn user_from_id(pool: &DbPool, id: i64) -> DbResult<super::user::User> { |     pub fn user_from_id(pool: &DbPool, id: i64) -> DbResult<Option<super::user::User>> { | ||||||
|         Ok(sessions::dsl::sessions |         Ok(sessions::dsl::sessions | ||||||
|             .inner_join(users::table) |             .inner_join(users::table) | ||||||
|             .filter(sessions::id.eq(id)) |             .filter(sessions::id.eq(id)) | ||||||
|             .select(User::as_select()) |             .select(User::as_select()) | ||||||
|             .get_result(&mut pool.get()?)?) |             .get_result(&mut pool.get()?) | ||||||
|  |             .optional()?) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn user(&self, pool: &DbPool) -> DbResult<super::user::User> { |     pub fn user(&self, pool: &DbPool) -> DbResult<Option<super::user::User>> { | ||||||
|         Self::user_from_id(pool, self.id) |         Self::user_from_id(pool, self.id) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -1,5 +1,16 @@ | ||||||
| // @generated automatically by Diesel CLI.
 | // @generated automatically by Diesel CLI.
 | ||||||
| 
 | 
 | ||||||
|  | diesel::table! { | ||||||
|  |     devices (id) { | ||||||
|  |         id -> BigInt, | ||||||
|  |         device_id -> Text, | ||||||
|  |         user_id -> BigInt, | ||||||
|  |         caption -> Text, | ||||||
|  |         #[sql_name = "type"] | ||||||
|  |         type_ -> Text, | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| diesel::table! { | diesel::table! { | ||||||
|     sessions (id) { |     sessions (id) { | ||||||
|         id -> BigInt, |         id -> BigInt, | ||||||
|  | @ -15,9 +26,11 @@ diesel::table! { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | diesel::joinable!(devices -> users (user_id)); | ||||||
| diesel::joinable!(sessions -> users (user_id)); | diesel::joinable!(sessions -> users (user_id)); | ||||||
| 
 | 
 | ||||||
| diesel::allow_tables_to_appear_in_same_query!( | diesel::allow_tables_to_appear_in_same_query!( | ||||||
|  |     devices, | ||||||
|     sessions, |     sessions, | ||||||
|     users, |     users, | ||||||
| ); | ); | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue