json serialisation

This commit is contained in:
Akbar Rahman 2023-12-21 16:43:48 +00:00
parent e8332ee093
commit eebbef6782
Signed by: alvierahman90
GPG Key ID: 6217899F07CA2BDF
10 changed files with 265 additions and 31 deletions

View File

@ -12,7 +12,10 @@ default = ["console_error_panic_hook"]
[dependencies]
wasm-bindgen = "0.2.84"
chrono = { version = "0.4.31", features = [ "clock" ] }
chrono = { version = "0.4.31", features = [ "clock", "serde" ] }
serde = { version = "1.0", features = [ "derive" ] }
serde_json = { version = "1.0", features = [ "std" ] }
serde_with = { version = "3.4.0", features = [ "std", "chrono_0_4", "json" ] }
# The `console_error_panic_hook` crate provides better debugging of panics by
# logging them with `console.error`. This is great for development, but requires

37
src/db.rs Normal file
View File

@ -0,0 +1,37 @@
pub mod json;
use crate::models::*;
use std::io;
use serde_json;
#[derive(Debug)]
pub enum Error {
Generic(String),
FsIo(String),
Json(String),
}
impl From<io::Error> for Error {
fn from(e: io::Error) -> Self {
Self::FsIo(e.to_string())
}
}
impl From<serde_json::Error> for Error {
fn from(e: serde_json::Error) -> Self{
Self::Json(e.to_string())
}
}
pub trait Storage {
fn add_category(&mut self, category: NewCategory) -> Result<i32, Error>;
fn add_series(&mut self, category_id: i32, series: NewSeries) -> Result<i32, Error>;
fn add_series_point(&mut self, category_id: i32, series_id: i32, series_point: NewSeriesPoint) -> Result<i32, Error>;
//fn add_user(&mut self, id: i32, user: NewUser) -> Result<User, Error>;
fn get_category(&self, id: i32) -> Option<Category>;
//fn get_series(&self, id: i32) -> Result<Series, Error>;
//fn get_user(&self, id: i32) -> Result<User, Error>;
//fn update_category(&mut self, id: i32, changeset: CategoryChangeset) -> Result<(), Error>;
//fn update_series(&mut self, id: i32, changeset: SeriesChangeset) -> Result<(), Error>;
//fn update_user(&mut self, id: i32, changeset: UserChangeset) -> Result<(), Error>;
}

136
src/db/json.rs Normal file
View File

@ -0,0 +1,136 @@
use super::*;
pub struct JsonDb {
pub value: String,
}
/// JsonDb is single user.
impl JsonDb {
pub fn new(value: Option<String>) -> Self {
match value {
Some(value) => JsonDb { value },
None => JsonDb { value: String::from("[]") },
}
}
fn load(&self) -> Result<Vec<Category>, Error> {
match serde_json::from_str::<Vec<Category>>(&self.value) {
Ok(d) => Ok(d),
Err(e) => Err(Error::from(e)),
}
}
fn save(&mut self, data: Vec<Category>) -> Result<(), Error> {
let data = serde_json::to_string_pretty(&data);
match data {
Ok(d) => {
self.value = d;
Ok(())
},
Err(e) => Err(Error::from(e)),
}
}
}
impl Storage for JsonDb {
fn add_category(&mut self, category: NewCategory) -> Result<i32, Error> {
let mut max_id = 1;
let mut data = self.load()?;
for cat in data.iter().clone() {
if cat.id > max_id {
max_id = cat.id
}
}
let created = Category::new(max_id+1, category);
data.push(created);
self.save(data)?;
Ok(max_id + 1)
}
fn add_series(&mut self, category_id: i32, series: NewSeries) -> Result<i32, Error> {
let mut max_id = 1;
let mut cat: Option<&mut Category> = None;
let mut data = self.load()?;
for cat_opt in data.iter_mut() {
if cat_opt.id == category_id {
cat = Some(cat_opt);
break;
}
}
if let None = cat {
return Err(Error::Generic ("Unable to find category".to_owned()));
}
let cat = cat.unwrap();
for series in cat.series.iter().clone() {
if series.id > max_id {
max_id = series.id;
}
}
let created = Series::new(max_id+1, series);
cat.series.push(created);
self.save(data)?;
Ok(max_id + 1)
}
fn add_series_point(&mut self, category_id: i32, series_id: i32, series_point: NewSeriesPoint) -> Result<i32, Error> {
let mut max_id = 1;
let mut cat: Option<&mut Category> = None;
let mut series: Option<&mut Series> = None;
let mut data = self.load()?;
for cat_opt in data.iter_mut() {
if cat_opt.id == category_id {
cat = Some(cat_opt);
break;
}
}
if let None = cat {
return Err(Error::Generic ("Unable to find category".to_owned()));
}
let cat = cat.unwrap();
for series_opt in cat.series.iter_mut() {
if series_opt.id == series_id {
series = Some(series_opt);
break;
}
}
if let None = series {
return Err(Error::Generic ("Unable to find series".to_owned()));
}
let series: &mut Series = series.unwrap();
for point in series.points.iter().clone() {
if point.id > max_id {
max_id = point.id;
}
}
let created = SeriesPoint::new(max_id + 1, series_point);
series.points.push(created);
self.save(data)?;
Ok(max_id + 1)
}
fn get_category(&self, id: i32) -> Option<Category> {
let data = self.load().ok()?;
for cat_opt in data {
if cat_opt.id == id {
return Some(cat_opt);
}
}
None
}
}

View File

@ -1,4 +1,5 @@
mod utils;
pub mod models;
pub mod db;
use wasm_bindgen::prelude::*;

View File

@ -1,9 +1,11 @@
pub mod category;
pub mod series;
pub mod series_point;
pub mod series_type;
mod category;
mod series;
mod series_point;
mod series_type;
mod user;
pub use category::*;
pub use series::*;
pub use series_point::*;
pub use series_type::*;
pub use user::*;

View File

@ -1,18 +1,19 @@
use crate::models::Series;
use serde::{ Serialize, Deserialize };
#[derive(Debug)]
#[derive(Debug, Serialize, Deserialize)]
pub struct Category {
id: i32,
name: String,
series: Vec<Series>,
pub id: i32,
pub name: String,
pub series: Vec<Series>,
}
impl Category {
pub fn new(id: i32, name: String) -> Category {
pub fn new(id: i32, new: NewCategory) -> Category {
Category {
id,
name,
series: vec![],
name: new.name,
series: new.series,
}
}
@ -20,3 +21,13 @@ impl Category {
self.series.push(series);
}
}
pub struct CategoryChangeset {
pub name: Option<String>,
pub series: Option<Vec<Series>>,
}
pub struct NewCategory {
pub name: String,
pub series: Vec<Series>,
}

View File

@ -1,23 +1,27 @@
use chrono;
use super::series_point::SeriesPoint;
use serde::{ Serialize, Deserialize };
use serde_with;
#[derive(Debug)]
#[serde_with::serde_as]
#[derive(Debug, Serialize, Deserialize)]
pub struct Series {
id: i32,
name: String,
repeat: chrono::Duration,
good: bool,
points: Vec<SeriesPoint>,
pub id: i32,
pub name: String,
#[serde_as(as = "serde_with::DurationSeconds<i64>")]
pub repeat: chrono::Duration,
pub good: bool,
pub points: Vec<SeriesPoint>,
}
impl Series {
pub fn new(id: i32, name: String, repeat: chrono::Duration, good: bool) -> Series {
pub fn new(id: i32, series: NewSeries) -> Series {
Series {
id,
name,
repeat,
good,
points: vec![],
name: series.name,
repeat: series.repeat,
good: series.good,
points: series.points,
}
}
@ -25,3 +29,17 @@ impl Series {
self.points.push(point);
}
}
pub struct SeriesChangeset {
pub name: Option<String>,
pub repeat: Option<chrono::Duration>,
pub good: Option<bool>,
pub points: Option<Vec<SeriesPoint>>,
}
pub struct NewSeries {
pub name: String,
pub repeat: chrono::Duration,
pub good: bool,
pub points: Vec<SeriesPoint>,
}

View File

@ -1,19 +1,25 @@
use chrono;
use super::series_type::SeriesType;
use serde::{ Serialize, Deserialize };
#[derive(Debug)]
#[derive(Debug, Serialize, Deserialize)]
pub struct SeriesPoint {
id: i32,
timestamp: chrono::NaiveDateTime,
value: SeriesType,
pub id: i32,
pub timestamp: chrono::NaiveDateTime,
pub value: SeriesType,
}
impl SeriesPoint {
pub fn new(id: i32, timestamp: chrono::NaiveDateTime, value: SeriesType) -> SeriesPoint {
pub fn new(id: i32, new: NewSeriesPoint) -> SeriesPoint {
SeriesPoint {
id,
timestamp,
value
timestamp: new.timestamp,
value: new.value,
}
}
}
pub struct NewSeriesPoint {
pub timestamp: chrono::NaiveDateTime,
pub value: SeriesType,
}

View File

@ -1,4 +1,6 @@
#[derive(Debug)]
use serde::{ Serialize, Deserialize };
#[derive(Debug, Serialize, Deserialize)]
pub enum SeriesType {
Bool(bool),
Count(u32),

18
src/models/user.rs Normal file
View File

@ -0,0 +1,18 @@
use serde::{ Serialize, Deserialize };
#[derive(Debug, Serialize, Deserialize)]
pub struct User {
id: i32,
name: String,
email: String,
}
pub struct UserChangeset {
name: Option<String>,
email: Option<String>,
}
pub struct NewUser {
name: String,
email: String,
}