v0.08
This commit is contained in:
@@ -6,6 +6,7 @@ edition = "2021"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
booksman-orm = { path = "../orm" }
|
booksman-orm = { path = "../orm" }
|
||||||
|
entity = { path = "../entity" }
|
||||||
axum = "^0.5"
|
axum = "^0.5"
|
||||||
axum-extra = { version = "^0.3", features = ["spa"] }
|
axum-extra = { version = "^0.3", features = ["spa"] }
|
||||||
clap = { version = "^3", features = ["derive"] }
|
clap = { version = "^3", features = ["derive"] }
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
use axum::{
|
use axum::{
|
||||||
http::{HeaderValue, Method},
|
http::{HeaderValue, Method},
|
||||||
response::IntoResponse,
|
response::IntoResponse,
|
||||||
routing::get,
|
routing::{get,post},
|
||||||
Json, Router,
|
Json, Router,
|
||||||
|
extract::{Extension, Form, Path, Query},
|
||||||
};
|
};
|
||||||
use axum_extra::routing::SpaRouter;
|
use axum_extra::routing::SpaRouter;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
@@ -13,6 +14,11 @@ use std::str::FromStr;
|
|||||||
use tower::ServiceBuilder;
|
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::{
|
||||||
|
sea_orm::{Database, DatabaseConnection},
|
||||||
|
Mutation as MutationCore, Query as QueryCore,
|
||||||
|
};
|
||||||
|
use ::entity::entities::{book,book_author,book_person,book_place,book_subject,book_time,book_isbn};
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Debug)]
|
#[derive(Deserialize, Serialize, Debug)]
|
||||||
struct Docs {
|
struct Docs {
|
||||||
@@ -29,21 +35,7 @@ struct Docs {
|
|||||||
subject: Option<Vec<String>>,
|
subject: Option<Vec<String>>,
|
||||||
time: Option<Vec<String>>,
|
time: Option<Vec<String>>,
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
impl Docs {
|
|
||||||
fn set_cover_url(&mut self) {
|
|
||||||
match self.cover_i {
|
|
||||||
Some(cover_i) => {
|
|
||||||
self.cover_url = Some(format!(
|
|
||||||
"https://covers.openlibrary.org/b/id/{}-L.jpg",
|
|
||||||
(cover_i.unwrap())
|
|
||||||
))
|
|
||||||
}
|
|
||||||
None => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
#[derive(Deserialize, Serialize, Debug)]
|
#[derive(Deserialize, Serialize, Debug)]
|
||||||
struct Books {
|
struct Books {
|
||||||
num_found: u32,
|
num_found: u32,
|
||||||
@@ -99,7 +91,10 @@ pub async fn main() {
|
|||||||
tracing_subscriber::fmt::init();
|
tracing_subscriber::fmt::init();
|
||||||
|
|
||||||
let app = Router::new()
|
let app = Router::new()
|
||||||
.route("/api/hello", get(hello))
|
.route("/api/search_openlibrary", get(search_openlibrary))
|
||||||
|
.route("/api/delete/:id", post(delete_book))
|
||||||
|
.route("/api/list", post(list_book))
|
||||||
|
.route("/api/create", post(create_book))
|
||||||
.merge(SpaRouter::new("/assets", opt.static_dir))
|
.merge(SpaRouter::new("/assets", opt.static_dir))
|
||||||
.layer(ServiceBuilder::new().layer(TraceLayer::new_for_http()))
|
.layer(ServiceBuilder::new().layer(TraceLayer::new_for_http()))
|
||||||
.layer(
|
.layer(
|
||||||
@@ -111,7 +106,7 @@ pub async fn main() {
|
|||||||
// or see this issue https://github.com/tokio-rs/axum/issues/849
|
// or see this issue https://github.com/tokio-rs/axum/issues/849
|
||||||
CorsLayer::new()
|
CorsLayer::new()
|
||||||
.allow_origin("http://localhost:8080".parse::<HeaderValue>().unwrap())
|
.allow_origin("http://localhost:8080".parse::<HeaderValue>().unwrap())
|
||||||
.allow_methods([Method::GET]),
|
.allow_methods([Method::GET, Method::POST]),
|
||||||
);
|
);
|
||||||
|
|
||||||
let sock_addr = SocketAddr::from((
|
let sock_addr = SocketAddr::from((
|
||||||
@@ -127,7 +122,7 @@ pub async fn main() {
|
|||||||
.expect("Unable to start server");
|
.expect("Unable to start server");
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn hello(
|
async fn search_openlibrary(
|
||||||
axum::extract::Query(params): axum::extract::Query<HashMap<String, String>>,
|
axum::extract::Query(params): axum::extract::Query<HashMap<String, String>>,
|
||||||
) -> impl IntoResponse {
|
) -> impl IntoResponse {
|
||||||
print!("Get items with query params: {:?}\n", params);
|
print!("Get items with query params: {:?}\n", params);
|
||||||
@@ -140,3 +135,49 @@ async fn hello(
|
|||||||
print!("Search token {:?}\n", search);
|
print!("Search token {:?}\n", search);
|
||||||
return Json(resjson);
|
return Json(resjson);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async fn delete_book(
|
||||||
|
Extension(ref conn): Extension<DatabaseConnection>,
|
||||||
|
Path(id): Path<i32>,
|
||||||
|
) -> impl IntoResponse {
|
||||||
|
MutationCore::delete_book(conn, id)
|
||||||
|
.await
|
||||||
|
.expect("could not delete book");
|
||||||
|
"success"
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn list_book(
|
||||||
|
Extension(ref conn): Extension<DatabaseConnection>,
|
||||||
|
) -> impl IntoResponse {
|
||||||
|
let books = QueryCore::find_books_in_page(conn,1,5)
|
||||||
|
.await
|
||||||
|
.expect("could not list books");
|
||||||
|
"success"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async fn create_book(
|
||||||
|
Extension(ref conn): Extension<DatabaseConnection>,
|
||||||
|
doc_sent : Form<Docs>,
|
||||||
|
) -> impl IntoResponse {
|
||||||
|
let book: book::Model = book::Model{
|
||||||
|
open_library_key: "NONE".to_string(),
|
||||||
|
title: (doc_sent.title.to_owned()),
|
||||||
|
edition_count: 1,
|
||||||
|
first_publish_year: 1,//(doc_sent.first_publish_year.unwrap().to_owned()),
|
||||||
|
median_page_count: 1, //(doc_sent.number_of_pages_median.unwrap().to_owned()),
|
||||||
|
goodread_id: "NONE".to_string(),
|
||||||
|
description: "NONE".to_string(),
|
||||||
|
comments: "NONE".to_string(),
|
||||||
|
cover: "NONE".to_string(),
|
||||||
|
rating: 1,
|
||||||
|
time_added: "NONE".to_string(),
|
||||||
|
id: 1,
|
||||||
|
location: "NONE".to_string(),
|
||||||
|
};
|
||||||
|
let created_book = MutationCore::create_book(conn, book)
|
||||||
|
.await
|
||||||
|
.expect("could not create book");
|
||||||
|
"success"
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,24 +1,114 @@
|
|||||||
//use ::entity::entities::prelude::Book;
|
//use ::entity::entities::prelude::Book;
|
||||||
//use ::entity::entities::{prelude::*, *};
|
//use ::entity::entities::{prelude::*, *};
|
||||||
|
use ::entity::entities::{book::Entity as Book};
|
||||||
|
//, book_author::Entity as Author, book_person::Entity as Person, book_place::Entity as Place, book_subject::Entity as Subject, book_time::Entity as Time, book_isbn::Entity as ISBN};
|
||||||
|
use ::entity::entities::{book,book_author,book_person,book_place,book_subject,book_time,book_isbn};
|
||||||
use sea_orm::*;
|
use sea_orm::*;
|
||||||
//use ::entity::entities::prelude::Book;
|
//use ::entity::entities::prelude::Book;
|
||||||
|
|
||||||
pub struct Mutation;
|
pub struct Mutation;
|
||||||
|
|
||||||
impl Mutation {
|
impl Mutation {
|
||||||
/* pub async fn create_post(
|
pub async fn create_book(
|
||||||
db: &DbConn,
|
db: &DbConn,
|
||||||
form_data: post::Model,
|
form_data: book::Model,
|
||||||
) -> Result<post::ActiveModel, DbErr> {
|
) -> Result<book::ActiveModel, DbErr> {
|
||||||
post::ActiveModel {
|
book::ActiveModel {
|
||||||
|
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()),
|
||||||
text: Set(form_data.text.to_owned()),
|
edition_count: Set(form_data.edition_count.to_owned()),
|
||||||
|
first_publish_year: Set(form_data.first_publish_year.to_owned()),
|
||||||
|
median_page_count: Set(form_data.median_page_count.to_owned()),
|
||||||
|
goodread_id: Set(form_data.goodread_id.to_owned()),
|
||||||
|
description: Set(form_data.description.to_owned()),
|
||||||
|
cover: Set(form_data.cover.to_owned()),
|
||||||
|
location: Set(form_data.location.to_owned()),
|
||||||
|
time_added: Set(form_data.time_added.to_owned()),
|
||||||
|
rating: Set(form_data.rating.to_owned()),
|
||||||
|
comments: Set(form_data.comments.to_owned()),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
.save(db)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn create_book_author(
|
||||||
|
db: &DbConn,
|
||||||
|
form_data: book_author::Model,
|
||||||
|
) -> Result<book_author::ActiveModel, DbErr> {
|
||||||
|
book_author::ActiveModel {
|
||||||
|
book_id: Set(form_data.book_id.to_owned()),
|
||||||
|
author_name: Set(form_data.author_name.to_owned()),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
.save(db)
|
.save(db)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn create_book_person(
|
||||||
|
db: &DbConn,
|
||||||
|
form_data: book_person::Model,
|
||||||
|
) -> Result<book_person::ActiveModel, DbErr> {
|
||||||
|
book_person::ActiveModel {
|
||||||
|
book_id: Set(form_data.book_id.to_owned()),
|
||||||
|
person: Set(form_data.person.to_owned()),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
.save(db)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn create_book_place(
|
||||||
|
db: &DbConn,
|
||||||
|
form_data: book_place::Model,
|
||||||
|
) -> Result<book_place::ActiveModel, DbErr> {
|
||||||
|
book_place::ActiveModel {
|
||||||
|
book_id: Set(form_data.book_id.to_owned()),
|
||||||
|
place: Set(form_data.place.to_owned()),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
.save(db)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
pub async fn create_book_subject(
|
||||||
|
db: &DbConn,
|
||||||
|
form_data: book_subject::Model,
|
||||||
|
) -> Result<book_subject::ActiveModel, DbErr> {
|
||||||
|
book_subject::ActiveModel {
|
||||||
|
book_id: Set(form_data.book_id.to_owned()),
|
||||||
|
subject: Set(form_data.subject.to_owned()),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
.save(db)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn create_book_time(
|
||||||
|
db: &DbConn,
|
||||||
|
form_data: book_time::Model,
|
||||||
|
) -> Result<book_time::ActiveModel, DbErr> {
|
||||||
|
book_time::ActiveModel {
|
||||||
|
book_id: Set(form_data.book_id.to_owned()),
|
||||||
|
time: Set(form_data.time.to_owned()),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
.save(db)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn create_book_isbn(
|
||||||
|
db: &DbConn,
|
||||||
|
form_data: book_isbn::Model,
|
||||||
|
) -> Result<book_isbn::ActiveModel, DbErr> {
|
||||||
|
book_isbn::ActiveModel {
|
||||||
|
book_id: Set(form_data.book_id.to_owned()),
|
||||||
|
isbn: Set(form_data.isbn.to_owned()),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
.save(db)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
/*
|
||||||
pub async fn update_post_by_id(
|
pub async fn update_post_by_id(
|
||||||
db: &DbConn,
|
db: &DbConn,
|
||||||
id: i32,
|
id: i32,
|
||||||
@@ -38,18 +128,18 @@ impl Mutation {
|
|||||||
.update(db)
|
.update(db)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
pub async fn delete_post(db: &DbConn, id: i32) -> Result<DeleteResult, DbErr> {
|
pub async fn delete_book(db: &DbConn, id: i32) -> Result<DeleteResult, DbErr> {
|
||||||
let post: post::ActiveModel = Post::find_by_id(id)
|
let book: book::ActiveModel = Book::find_by_id(id)
|
||||||
.one(db)
|
.one(db)
|
||||||
.await?
|
.await?
|
||||||
.ok_or(DbErr::Custom("Cannot find post.".to_owned()))
|
.ok_or(DbErr::Custom("Cannot find book.".to_owned()))
|
||||||
.map(Into::into)?;
|
.map(Into::into)?;
|
||||||
|
|
||||||
post.delete(db).await
|
book.delete(db).await
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
/* pub async fn delete_all_books(db: &DbConn) -> Result<DeleteResult, DbErr> {
|
pub async fn delete_all_books(db: &DbConn) -> Result<DeleteResult, DbErr> {
|
||||||
Book::delete_many().exec(db).await
|
Book::delete_many().exec(db).await
|
||||||
} */
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,32 @@
|
|||||||
use ::entity::entities::book::Entity as Book;
|
use ::entity::entities::{book::Entity as Book};
|
||||||
use ::entity::entities::book;
|
//, book_author::Entity as Author, book_person::Entity as Person, book_place::Entity as Place, book_subject::Entity as Subject, book_time::Entity as Time, book_isbn::Entity as ISBN};
|
||||||
|
use ::entity::entities::{book,book_author,book_person,book_place,book_subject,book_time,book_isbn};
|
||||||
//use ::entity::entities::{prelude::*, *};
|
//use ::entity::entities::{prelude::*, *};
|
||||||
use sea_orm::*;
|
use sea_orm::*;
|
||||||
|
//use sea_query::Expr;
|
||||||
|
|
||||||
|
#[derive(FromQueryResult)]
|
||||||
|
pub struct BookAndMeta {
|
||||||
|
pub id: i32,
|
||||||
|
pub open_library_key: String,
|
||||||
|
pub title: String,
|
||||||
|
pub edition_count: i32,
|
||||||
|
pub first_publish_year: i32,
|
||||||
|
pub median_page_count: i32,
|
||||||
|
pub goodread_id: String,
|
||||||
|
pub description: String,
|
||||||
|
pub cover: String,
|
||||||
|
pub location: String,
|
||||||
|
pub time_added: String,
|
||||||
|
pub rating: i32,
|
||||||
|
pub comments: String,
|
||||||
|
pub author_name: String,
|
||||||
|
pub person: String,
|
||||||
|
pub place: String,
|
||||||
|
pub subject: String,
|
||||||
|
pub time: String,
|
||||||
|
pub isbn: String,
|
||||||
|
}
|
||||||
//use ::entity::entities::prelude::Book;
|
//use ::entity::entities::prelude::Book;
|
||||||
|
|
||||||
pub struct Query;
|
pub struct Query;
|
||||||
@@ -11,8 +36,16 @@ impl Query {
|
|||||||
Book::find_by_id(id).one(db).await
|
Book::find_by_id(id).one(db).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* pub async fn find_bookplusmeta_by_id(db: &DbConn, id: i32) -> Result<Option<(book::Model, Vec<book_author::Model>, Vec<book_person::Model>)>, DbErr> {
|
||||||
|
let book = Book::find_by_id(id).one(db).await?.unwrap();
|
||||||
|
let authors = book.find_related(Author).all(db).await?;
|
||||||
|
let persons = book.find_related(Person).all(db).await?;
|
||||||
|
Ok(Some((book, authors, persons)))
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
/// If ok, returns (post models, num pages).
|
/// If ok, returns (post models, num pages).
|
||||||
pub async fn find_posts_in_page(
|
pub async fn find_books_in_page(
|
||||||
db: &DbConn,
|
db: &DbConn,
|
||||||
page: usize,
|
page: usize,
|
||||||
posts_per_page: usize,
|
posts_per_page: usize,
|
||||||
@@ -26,5 +59,34 @@ impl Query {
|
|||||||
// Fetch paginated posts
|
// Fetch paginated posts
|
||||||
paginator.fetch_page(page - 1).await.map(|p| (p, num_pages))
|
paginator.fetch_page(page - 1).await.map(|p| (p, num_pages))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn find_books_plus_meta_in_page(
|
||||||
|
db: &DbConn,
|
||||||
|
page: usize,
|
||||||
|
posts_per_page: usize,
|
||||||
|
) -> Result<(Vec<BookAndMeta>, usize), DbErr> {
|
||||||
|
// Setup paginator
|
||||||
|
let books = Self::find_books_in_page(db,page,posts_per_page).await?;
|
||||||
|
let book_ids: Vec<i32> = books.0.clone().into_iter().map(|b| b.id).collect();
|
||||||
|
/* let paginator1 = Book::find().filter(
|
||||||
|
Condition::any()
|
||||||
|
.add(book::Column::Id.is_in(book_ids))
|
||||||
|
).find_with_related(Author).all(db).await?;*/
|
||||||
|
let paginator2 = Book::find()
|
||||||
|
.filter(Condition::any()
|
||||||
|
.add(book::Column::Id.is_in(book_ids)))
|
||||||
|
.join(JoinType::LeftJoin, book_author::Relation::Book.def())
|
||||||
|
.join(JoinType::LeftJoin, book_person::Relation::Book.def())
|
||||||
|
.join(JoinType::LeftJoin, book_place::Relation::Book.def())
|
||||||
|
.join(JoinType::LeftJoin, book_subject::Relation::Book.def())
|
||||||
|
.join(JoinType::LeftJoin, book_time::Relation::Book.def())
|
||||||
|
.join(JoinType::LeftJoin, book_isbn::Relation::Book.def())
|
||||||
|
.column_as(book::Column::Id, "id")
|
||||||
|
.into_model::<BookAndMeta>()
|
||||||
|
.all(db).await?;
|
||||||
|
|
||||||
|
Ok((paginator2,books.1))
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user