This commit is contained in:
2022-10-26 16:49:55 +05:30
parent cd62df8082
commit de6519c701
6 changed files with 195 additions and 48 deletions

1
backend/Cargo.lock generated
View File

@@ -423,6 +423,7 @@ dependencies = [
"clap", "clap",
"entity", "entity",
"error-chain", "error-chain",
"itertools",
"log", "log",
"reqwest", "reqwest",
"sea-orm", "sea-orm",

View File

@@ -20,6 +20,7 @@ tower = "^0.4"
tower-http = { version = "^0.3", features = ["full"] } tower-http = { version = "^0.3", features = ["full"] }
tracing = "^0.1" tracing = "^0.1"
tracing-subscriber = "^0.3" tracing-subscriber = "^0.3"
itertools = "0.10"
[dependencies.sea-orm] [dependencies.sea-orm]
version = "^0.9.2" # sea-orm version version = "^0.9.2" # sea-orm version

View File

@@ -15,19 +15,47 @@ use tower::ServiceBuilder;
use tower_http::cors::CorsLayer; use tower_http::cors::CorsLayer;
use tower_http::trace::TraceLayer; use tower_http::trace::TraceLayer;
use booksman_orm::{ use booksman_orm::{
sea_orm::{Database, DatabaseConnection}, sea_orm::{Database, DatabaseConnection, ActiveValue},
Mutation as MutationCore, Query as QueryCore, Mutation as MutationCore, Query as QueryCore,
}; };
use itertools::Itertools;
use std::iter::Peekable;
use ::entity::entities::{book,book_author,book_person,book_place,book_subject,book_time,book_isbn}; use ::entity::entities::{book,book_author,book_person,book_place,book_subject,book_time,book_isbn};
#[derive(Deserialize, Serialize, Debug)] #[derive(Deserialize, Serialize, Debug, Clone)]
struct BookUI {
id: i32,
open_library_key: Option<String>,
title: String,
edition_count: Option<i32>,
first_publish_year: Option<i32>,
median_page_count: Option<i32>,
goodread_id: Option<String>,
description: Option<String>,
cover: Option<String>,
location: Option<String>,
time_added: Option<String>,
rating: Option<i32>,
comments: Option<String>,
author_name: Option<Vec<String>>,
person: Option<Vec<String>>,
place: Option<Vec<String>>,
subject: Option<Vec<String>>,
time: Option<Vec<String>>,
isbn: Option<Vec<String>>,
}
#[derive(Deserialize, Serialize, Debug, Clone)]
struct Docs { struct Docs {
key: String, key: String,
title: String, title: String,
first_publish_year: Option<u32>, edition_count: Option<i32>,
number_of_pages_median: Option<u32>, first_publish_year: Option<i32>,
number_of_pages_median: Option<i32>,
goodread_id: Option<String>,
description: Option<String>,
isbn: Option<Vec<String>>, isbn: Option<Vec<String>>,
cover_i: Option<u32>, cover_i: Option<i32>,
cover_url: Option<String>, cover_url: Option<String>,
author_name: Option<Vec<String>>, author_name: Option<Vec<String>>,
person: Option<Vec<String>>, person: Option<Vec<String>>,
@@ -133,9 +161,35 @@ async fn search_openlibrary(
resjson.docs.truncate(10); resjson.docs.truncate(10);
resjson.set_all_cover_urls(); resjson.set_all_cover_urls();
print!("Search token {:?}\n", search); print!("Search token {:?}\n", search);
return Json(resjson); let mut vec = Vec::with_capacity(10);
for i in 0..10 as usize {
let doc = resjson.docs[i].clone();
vec.push(
BookUI{
id: (i+1) as i32,
open_library_key: Some(doc.key),
title: doc.title,
edition_count: doc.edition_count,
first_publish_year: doc.first_publish_year,
median_page_count: doc.number_of_pages_median,
goodread_id: doc.goodread_id,
description: doc.description,
cover: doc.cover_url,
location: None,
time_added: None,
rating: None,
comments: None,
author_name: doc.author_name,
person: doc.person,
place: doc.place,
subject: doc.subject,
time: doc.time,
isbn: doc.isbn
}
);
}
return Json(vec);
} }
async fn delete_book( async fn delete_book(
Extension(ref conn): Extension<DatabaseConnection>, Extension(ref conn): Extension<DatabaseConnection>,
@@ -150,34 +204,126 @@ async fn delete_book(
async fn list_book( async fn list_book(
Extension(ref conn): Extension<DatabaseConnection>, Extension(ref conn): Extension<DatabaseConnection>,
) -> impl IntoResponse { ) -> impl IntoResponse {
let books = QueryCore::find_books_in_page(conn,1,5) let books = QueryCore::find_books_plus_meta_in_page(conn,1,5)
.await .await
.expect("could not list books"); .expect("could not list books");
"success" let res: Vec<BookUI> = (books.0).iter()
.group_by(|x| (x.id, x.title.clone()) ).into_iter().peekable()
.map(|((id,title), group )| BookUI{
id,
title,
open_library_key: group.map( |u| u.open_library_key).peek(),
edition_count: group.clone().map(|u| u.edition_count).next(),
first_publish_year: group.clone().map(|u| u.first_publish_year).next(),
median_page_count: group.clone().map(|u| u.median_page_count).next(),
goodread_id: group.clone().map(|u| u.goodread_id).next(),
description: group.clone().map(|u| u.description).next(),
cover: group.clone().map(|u| u.cover).next(),
location: group.clone().map(|u| u.location).next(),
time_added: group.clone().map(|u| u.time_added).next(),
rating: group.clone().map(|u| u.rating).next(),
comments: group.clone().map(|u| u.comments).next(),
author_name: Some(group.map(|u| u.author_name).collect()),
person: Some(group.map(|u| u.person).collect()),
place: Some(group.map(|u| u.place).collect()),
subject: Some(group.map(|u| u.subject).collect()),
time: Some(group.map(|u| u.time).collect()),
isbn: Some(group.map(|u| u.isbn).collect()),
}).collect();
return Json(res);
// "success"
} }
async fn create_book( async fn create_book(
Extension(ref conn): Extension<DatabaseConnection>, Extension(ref conn): Extension<DatabaseConnection>,
doc_sent : Form<Docs>, doc_sent : Form<BookUI>,
) -> impl IntoResponse { ) -> impl IntoResponse {
let book: book::Model = book::Model{ let book: book::Model = book::Model{
open_library_key: "NONE".to_string(), open_library_key: doc_sent.open_library_key.to_owned(),
title: (doc_sent.title.to_owned()), title: (doc_sent.title.to_owned()),
edition_count: 1, edition_count: doc_sent.edition_count.to_owned(),
first_publish_year: 1,//(doc_sent.first_publish_year.unwrap().to_owned()), first_publish_year: (doc_sent.first_publish_year.to_owned()),
median_page_count: 1, //(doc_sent.number_of_pages_median.unwrap().to_owned()), median_page_count: (doc_sent.median_page_count.to_owned()),
goodread_id: "NONE".to_string(), goodread_id: doc_sent.goodread_id.to_owned(),
description: "NONE".to_string(), description: doc_sent.description.to_owned(),
comments: "NONE".to_string(), comments: doc_sent.comments.to_owned(),
cover: "NONE".to_string(), cover: doc_sent.cover.to_owned(),
rating: 1, rating: doc_sent.rating.to_owned(),
time_added: "NONE".to_string(), time_added: doc_sent.time_added.to_owned(),
id: 1, id: 1,
location: "NONE".to_string(), location: doc_sent.location.to_owned(),
}; };
let created_book = MutationCore::create_book(conn, book) let created_book = MutationCore::create_book(conn, book)
.await .await
.expect("could not create book"); .expect("could not create book");
for author_name in doc_sent.author_name.as_ref().unwrap().iter() {
let record : book_author::Model = book_author::Model{
id: 1,
book_id: (created_book.last_insert_id),
author_name: author_name.to_owned(),
};
MutationCore::create_book_author(conn, record)
.await
.expect("could not create book");
}
for person in doc_sent.person.as_ref().unwrap().iter() {
let record : book_person::Model = book_person::Model{
id: 1,
book_id: (created_book.last_insert_id),
person: person.to_owned(),
};
MutationCore::create_book_person(conn, record)
.await
.expect("could not create book");
}
for place in doc_sent.place.as_ref().unwrap().iter() {
let record : book_place::Model = book_place::Model{
id: 1,
book_id: (created_book.last_insert_id),
place: place.to_owned(),
};
MutationCore::create_book_place(conn, record)
.await
.expect("could not create book");
}
for subject in doc_sent.subject.as_ref().unwrap().iter() {
let record : book_subject::Model = book_subject::Model{
id: 1,
book_id: (created_book.last_insert_id),
subject: subject.to_owned(),
};
MutationCore::create_book_subject(conn, record)
.await
.expect("could not create book");
}
for time in doc_sent.time.as_ref().unwrap().iter() {
let record : book_time::Model = book_time::Model{
id: 1,
book_id: (created_book.last_insert_id),
time: time.to_owned(),
};
MutationCore::create_book_time(conn, record)
.await
.expect("could not create book");
}
for isbn in doc_sent.isbn.as_ref().unwrap().iter() {
let record : book_isbn::Model = book_isbn::Model{
id: 1,
book_id: (created_book.last_insert_id),
isbn: isbn.to_owned(),
};
MutationCore::create_book_isbn(conn, record)
.await
.expect("could not create book");
}
"success" "success"
} }

View File

@@ -7,18 +7,18 @@ use sea_orm::entity::prelude::*;
pub struct Model { pub struct Model {
#[sea_orm(primary_key)] #[sea_orm(primary_key)]
pub id: i32, pub id: i32,
pub open_library_key: String, pub open_library_key: Option<String>,
pub title: String, pub title: String,
pub edition_count: i32, pub edition_count: Option<i32>,
pub first_publish_year: i32, pub first_publish_year: Option<i32>,
pub median_page_count: i32, pub median_page_count: Option<i32>,
pub goodread_id: String, pub goodread_id: Option<String>,
pub description: String, pub description: Option<String>,
pub cover: String, pub cover: Option<String>,
pub location: String, pub location: Option<String>,
pub time_added: String, pub time_added: Option<String>,
pub rating: i32, pub rating: Option<i32>,
pub comments: String, pub comments: Option<String>,
} }
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]

View File

@@ -22,18 +22,18 @@ impl MigrationTrait for Migration {
.auto_increment() .auto_increment()
.primary_key(), .primary_key(),
) )
.col(ColumnDef::new(Book::OpenLibraryKey).string().not_null()) .col(ColumnDef::new(Book::OpenLibraryKey).string())
.col(ColumnDef::new(Book::Title).string().not_null()) .col(ColumnDef::new(Book::Title).string().not_null())
.col(ColumnDef::new(Book::EditionCount).integer().not_null()) .col(ColumnDef::new(Book::EditionCount).integer())
.col(ColumnDef::new(Book::FirstPublishYear).integer().not_null()) .col(ColumnDef::new(Book::FirstPublishYear).integer())
.col(ColumnDef::new(Book::MedianPageCount).integer().not_null()) .col(ColumnDef::new(Book::MedianPageCount).integer())
.col(ColumnDef::new(Book::GoodreadId).string().not_null()) .col(ColumnDef::new(Book::GoodreadId).string())
.col(ColumnDef::new(Book::Description).string().not_null()) .col(ColumnDef::new(Book::Description).string())
.col(ColumnDef::new(Book::Cover).string().not_null()) .col(ColumnDef::new(Book::Cover).string())
.col(ColumnDef::new(Book::Location).string().not_null()) .col(ColumnDef::new(Book::Location).string())
.col(ColumnDef::new(Book::TimeAdded).time().not_null()) .col(ColumnDef::new(Book::TimeAdded).time())
.col(ColumnDef::new(Book::Rating).integer().not_null()) .col(ColumnDef::new(Book::Rating).integer())
.col(ColumnDef::new(Book::Comments).string().not_null()) .col(ColumnDef::new(Book::Comments).string())
.to_owned(), .to_owned(),
) )
.await; .await;

View File

@@ -12,8 +12,8 @@ impl Mutation {
pub async fn create_book( pub async fn create_book(
db: &DbConn, db: &DbConn,
form_data: book::Model, form_data: book::Model,
) -> Result<book::ActiveModel, DbErr> { ) -> Result<InsertResult<book::ActiveModel>, DbErr> {
book::ActiveModel { let record = book::ActiveModel {
open_library_key: Set(form_data.open_library_key.to_owned()), open_library_key: Set(form_data.open_library_key.to_owned()),
title: Set(form_data.title.to_owned()), title: Set(form_data.title.to_owned()),
edition_count: Set(form_data.edition_count.to_owned()), edition_count: Set(form_data.edition_count.to_owned()),
@@ -27,9 +27,8 @@ impl Mutation {
rating: Set(form_data.rating.to_owned()), rating: Set(form_data.rating.to_owned()),
comments: Set(form_data.comments.to_owned()), comments: Set(form_data.comments.to_owned()),
..Default::default() ..Default::default()
} };
.save(db) Book::insert(record).exec(db).await
.await
} }
pub async fn create_book_author( pub async fn create_book_author(