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; | ||||
| mod schema; | ||||
| 
 | ||||
| pub use models::device::{Device, NewDevice}; | ||||
| pub use models::session::Session; | ||||
| 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 user; | ||||
|  |  | |||
|  | @ -23,15 +23,16 @@ impl Session { | |||
|             .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 | ||||
|             .inner_join(users::table) | ||||
|             .filter(sessions::id.eq(id)) | ||||
|             .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) | ||||
|     } | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,5 +1,16 @@ | |||
| // @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! { | ||||
|     sessions (id) { | ||||
|         id -> BigInt, | ||||
|  | @ -15,9 +26,11 @@ diesel::table! { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| diesel::joinable!(devices -> users (user_id)); | ||||
| diesel::joinable!(sessions -> users (user_id)); | ||||
| 
 | ||||
| diesel::allow_tables_to_appear_in_same_query!( | ||||
|     devices, | ||||
|     sessions, | ||||
|     users, | ||||
| ); | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue