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"
|
chrono = "0.4"
|
||||||
diesel = { version = "2.2", features = ["sqlite", "returning_clauses_for_sqlite_3_35", "chrono"] }
|
diesel = { version = "2.2", features = ["sqlite", "returning_clauses_for_sqlite_3_35", "chrono"] }
|
||||||
dotenvy = "0.15"
|
dotenvy = "0.15"
|
||||||
|
serde = { version = "1", features = ["derive"] }
|
||||||
|
serde_json = "1"
|
||||||
tokio = { version = "1", features = ["full"] }
|
tokio = { version = "1", features = ["full"] }
|
|
@ -1,69 +1,40 @@
|
||||||
use std::fmt::{Display, Write};
|
use std::fmt::Display;
|
||||||
use diesel::{
|
use diesel::{
|
||||||
backend::Backend, deserialize::{FromSql, FromSqlRow}, serialize::ToSql, sql_types::Text, sqlite::Sqlite
|
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)]
|
#[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 {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
f.write_char('[')?;
|
f.write_str(&serde_json::to_string(&self).unwrap())
|
||||||
f.write_str(
|
|
||||||
&self
|
|
||||||
.0
|
|
||||||
.iter()
|
|
||||||
.map(|v| "\"".to_owned() + &v.replace("\"", "\\\"") + "\"")
|
|
||||||
.collect::<Vec<String>>()
|
|
||||||
.join(",")
|
|
||||||
)?;
|
|
||||||
f.write_char(']')
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<String> for List<String> {
|
impl<A> From<String> for List<A>
|
||||||
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>
|
|
||||||
where
|
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> {
|
fn from_sql(bytes: <Sqlite as Backend>::RawValue<'_>) -> diesel::deserialize::Result<Self> {
|
||||||
let str = <String as FromSql<Text, Sqlite>>::from_sql(bytes)?;
|
let str = <String as FromSql<Text, Sqlite>>::from_sql(bytes)?;
|
||||||
|
@ -71,9 +42,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToSql<Text, Sqlite> for List<String>
|
impl<V: std::fmt::Debug + std::clone::Clone + Serialize> ToSql<Text, Sqlite> for List<V>
|
||||||
where
|
|
||||||
String: ToSql<Text, Sqlite>,
|
|
||||||
{
|
{
|
||||||
fn to_sql<'b>(
|
fn to_sql<'b>(
|
||||||
&'b self,
|
&'b self,
|
||||||
|
|
|
@ -16,10 +16,23 @@
|
||||||
|
|
||||||
use chrono::NaiveDateTime;
|
use chrono::NaiveDateTime;
|
||||||
use diesel::prelude::*;
|
use diesel::prelude::*;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::database::schema;
|
use crate::database::schema;
|
||||||
use crate::database::list::List;
|
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)]
|
#[derive(Queryable, Selectable)]
|
||||||
#[diesel(table_name = schema::date_entries)]
|
#[diesel(table_name = schema::date_entries)]
|
||||||
#[diesel(check_for_backend(diesel::sqlite::Sqlite))]
|
#[diesel(check_for_backend(diesel::sqlite::Sqlite))]
|
||||||
|
@ -44,3 +57,72 @@ pub struct Entry {
|
||||||
location_entry: Option<String>,
|
location_entry: Option<String>,
|
||||||
date_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