Improve List implementation and finish model creation
This commit is contained in:
parent
b7b938c564
commit
d6a1cc2feb
3 changed files with 111 additions and 58 deletions
|
@ -8,4 +8,6 @@ axum = { version = "0.7" }
|
|||
chrono = "0.4"
|
||||
diesel = { version = "2.2", features = ["sqlite", "returning_clauses_for_sqlite_3_35", "chrono"] }
|
||||
dotenvy = "0.15"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
tokio = { version = "1", features = ["full"] }
|
|
@ -1,69 +1,40 @@
|
|||
use std::fmt::{Display, Write};
|
||||
use std::fmt::Display;
|
||||
use diesel::{
|
||||
backend::Backend, deserialize::{FromSql, FromSqlRow}, serialize::ToSql, sql_types::Text, sqlite::Sqlite
|
||||
};
|
||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||
|
||||
#[derive(FromSqlRow, Debug, Clone)]
|
||||
#[derive(FromSqlRow, Deserialize, Serialize, Debug, Clone)]
|
||||
#[serde(transparent)]
|
||||
#[repr(transparent)]
|
||||
pub struct List<V: std::fmt::Debug>(pub Vec<V>);
|
||||
pub struct List<V: std::fmt::Debug + std::clone::Clone>(pub Vec<V>);
|
||||
|
||||
impl Display for List<String> {
|
||||
impl<V: std::fmt::Debug + std::clone::Clone> List<V> {
|
||||
fn from_vec(vec: Vec<V>) -> Self {
|
||||
Self(vec)
|
||||
}
|
||||
|
||||
fn into_vec(self) -> Vec<V> {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: Serialize + std::fmt::Debug + std::clone::Clone> Display for List<A> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_char('[')?;
|
||||
f.write_str(
|
||||
&self
|
||||
.0
|
||||
.iter()
|
||||
.map(|v| "\"".to_owned() + &v.replace("\"", "\\\"") + "\"")
|
||||
.collect::<Vec<String>>()
|
||||
.join(",")
|
||||
)?;
|
||||
f.write_char(']')
|
||||
f.write_str(&serde_json::to_string(&self).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for List<String> {
|
||||
fn from(mut value: String) -> Self {
|
||||
if value.starts_with('[') {
|
||||
value.remove(0);
|
||||
}
|
||||
|
||||
if value.ends_with(']') {
|
||||
value.pop();
|
||||
}
|
||||
|
||||
let char_len = value.chars().count();
|
||||
let mut values = Vec::new();
|
||||
let mut current = String::new();
|
||||
let mut writing_str = false;
|
||||
let mut escape_next = false;
|
||||
|
||||
for (i, ch) in value.chars().enumerate() {
|
||||
if i == char_len - 1 {
|
||||
values.push(current);
|
||||
current = String::new();
|
||||
} else if escape_next {
|
||||
current.push(ch);
|
||||
escape_next = false;
|
||||
} else if ch == '\\' {
|
||||
escape_next = true;
|
||||
} else if ch == '\"' {
|
||||
writing_str = !writing_str;
|
||||
} else if ch == ',' && !writing_str {
|
||||
values.push(current);
|
||||
current = String::new();
|
||||
} else if writing_str {
|
||||
current.push(ch);
|
||||
}
|
||||
}
|
||||
|
||||
List(values)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromSql<Text, Sqlite> for List<String>
|
||||
impl<A> From<String> for List<A>
|
||||
where
|
||||
String: FromSql<Text, Sqlite>,
|
||||
A: DeserializeOwned + std::fmt::Debug + std::clone::Clone,
|
||||
{
|
||||
fn from(value: String) -> Self {
|
||||
serde_json::from_str(&value).expect("failed to deserialize list")
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: std::fmt::Debug + std::clone::Clone + DeserializeOwned> FromSql<Text, Sqlite> for List<V>
|
||||
{
|
||||
fn from_sql(bytes: <Sqlite as Backend>::RawValue<'_>) -> diesel::deserialize::Result<Self> {
|
||||
let str = <String as FromSql<Text, Sqlite>>::from_sql(bytes)?;
|
||||
|
@ -71,9 +42,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl ToSql<Text, Sqlite> for List<String>
|
||||
where
|
||||
String: ToSql<Text, Sqlite>,
|
||||
impl<V: std::fmt::Debug + std::clone::Clone + Serialize> ToSql<Text, Sqlite> for List<V>
|
||||
{
|
||||
fn to_sql<'b>(
|
||||
&'b self,
|
||||
|
|
|
@ -16,10 +16,23 @@
|
|||
|
||||
use chrono::NaiveDateTime;
|
||||
use diesel::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::database::schema;
|
||||
use crate::database::list::List;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct UniversalId {
|
||||
provider: String,
|
||||
id: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct LocationCoordinates {
|
||||
latitude: f64,
|
||||
longitude: f64,
|
||||
}
|
||||
|
||||
#[derive(Queryable, Selectable)]
|
||||
#[diesel(table_name = schema::date_entries)]
|
||||
#[diesel(check_for_backend(diesel::sqlite::Sqlite))]
|
||||
|
@ -44,3 +57,72 @@ pub struct Entry {
|
|||
location_entry: Option<String>,
|
||||
date_entry: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Queryable, Selectable)]
|
||||
#[diesel(table_name = schema::heirs)]
|
||||
#[diesel(check_for_backend(diesel::sqlite::Sqlite))]
|
||||
pub struct Heir {
|
||||
id: String,
|
||||
user_id: String,
|
||||
created_at: NaiveDateTime,
|
||||
name: String,
|
||||
email: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Queryable, Selectable)]
|
||||
#[diesel(table_name = schema::limits)]
|
||||
#[diesel(check_for_backend(diesel::sqlite::Sqlite))]
|
||||
pub struct Limit {
|
||||
id: String,
|
||||
current_asset_count: i32,
|
||||
max_asset_count: i32,
|
||||
}
|
||||
|
||||
#[derive(Queryable, Selectable)]
|
||||
#[diesel(table_name = schema::location_entries)]
|
||||
#[diesel(check_for_backend(diesel::sqlite::Sqlite))]
|
||||
pub struct LocationEntry {
|
||||
id: String,
|
||||
location_text: Option<String>,
|
||||
/// JSON value: { latitude: number, longitude: number }
|
||||
location_coordinates: Option<String>,
|
||||
}
|
||||
|
||||
impl LocationEntry {
|
||||
pub fn location_coordinates(&self) -> Option<LocationCoordinates> {
|
||||
self.location_coordinates.as_ref().map(|v| serde_json::from_str(&v).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Queryable, Selectable)]
|
||||
#[diesel(table_name = schema::music_entries)]
|
||||
#[diesel(check_for_backend(diesel::sqlite::Sqlite))]
|
||||
pub struct MusicEntry {
|
||||
id: String,
|
||||
artist: String,
|
||||
title: String,
|
||||
links: List<String>,
|
||||
universal_ids: List<UniversalId>,
|
||||
}
|
||||
|
||||
#[derive(Queryable, Selectable)]
|
||||
#[diesel(table_name = schema::session_keys)]
|
||||
#[diesel(check_for_backend(diesel::sqlite::Sqlite))]
|
||||
pub struct SessionKey {
|
||||
key: String,
|
||||
user_id: String,
|
||||
}
|
||||
|
||||
#[derive(Queryable, Selectable)]
|
||||
#[diesel(table_name = schema::users)]
|
||||
#[diesel(check_for_backend(diesel::sqlite::Sqlite))]
|
||||
pub struct User {
|
||||
id: String,
|
||||
created_at: NaiveDateTime,
|
||||
last_connected_at: NaiveDateTime,
|
||||
email: String,
|
||||
password: String,
|
||||
name: String,
|
||||
limits: String,
|
||||
assets: String,
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue