v0.07
This commit is contained in:
46
backend/Cargo.lock
generated
46
backend/Cargo.lock
generated
@@ -347,20 +347,7 @@ dependencies = [
|
|||||||
name = "backend"
|
name = "backend"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"axum",
|
"booksman-api",
|
||||||
"axum-extra",
|
|
||||||
"clap",
|
|
||||||
"error-chain",
|
|
||||||
"log",
|
|
||||||
"reqwest",
|
|
||||||
"sea-orm",
|
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
"tokio",
|
|
||||||
"tower",
|
|
||||||
"tower-http",
|
|
||||||
"tracing",
|
|
||||||
"tracing-subscriber",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -426,6 +413,37 @@ dependencies = [
|
|||||||
"once_cell",
|
"once_cell",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "booksman-api"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"axum",
|
||||||
|
"axum-extra",
|
||||||
|
"booksman-orm",
|
||||||
|
"clap",
|
||||||
|
"error-chain",
|
||||||
|
"log",
|
||||||
|
"reqwest",
|
||||||
|
"sea-orm",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"tokio",
|
||||||
|
"tower",
|
||||||
|
"tower-http",
|
||||||
|
"tracing",
|
||||||
|
"tracing-subscriber",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "booksman-orm"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"chrono",
|
||||||
|
"entity",
|
||||||
|
"sea-orm",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "brotli"
|
name = "brotli"
|
||||||
version = "3.3.4"
|
version = "3.3.4"
|
||||||
|
|||||||
@@ -5,29 +5,8 @@ edition = "2021"
|
|||||||
|
|
||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
members = [".", "entity", "migration"]
|
members = [".", "entity", "migration", "orm", "api"]
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
axum = "^0.5"
|
booksman-api = { path = "api" }
|
||||||
axum-extra = { version = "^0.3", features = ["spa"] }
|
|
||||||
clap = { version = "^3", features = ["derive"] }
|
|
||||||
error-chain = "0.12.4"
|
|
||||||
log = "^0.4"
|
|
||||||
reqwest = {version = "0.11.11", features = ["json"]}
|
|
||||||
serde = { version = "^1.0", features = ["derive"] }
|
|
||||||
serde_json = "^1.0"
|
|
||||||
tokio = { version = "^1", features = ["full"] }
|
|
||||||
tower = "^0.4"
|
|
||||||
tower-http = { version = "^0.3", features = ["full"] }
|
|
||||||
tracing = "^0.1"
|
|
||||||
tracing-subscriber = "^0.3"
|
|
||||||
|
|
||||||
[dependencies.sea-orm]
|
|
||||||
version = "^0.9.2" # sea-orm version
|
|
||||||
features = [
|
|
||||||
"debug-print",
|
|
||||||
"runtime-tokio-native-tls",
|
|
||||||
"sqlx-sqlite",
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|||||||
31
backend/api/Cargo.toml
Normal file
31
backend/api/Cargo.toml
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
[package]
|
||||||
|
name = "booksman-api"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
booksman-orm = { path = "../orm" }
|
||||||
|
axum = "^0.5"
|
||||||
|
axum-extra = { version = "^0.3", features = ["spa"] }
|
||||||
|
clap = { version = "^3", features = ["derive"] }
|
||||||
|
error-chain = "0.12.4"
|
||||||
|
log = "^0.4"
|
||||||
|
reqwest = {version = "0.11.11", features = ["json"]}
|
||||||
|
serde = { version = "^1.0", features = ["derive"] }
|
||||||
|
serde_json = "^1.0"
|
||||||
|
tokio = { version = "^1", features = ["full"] }
|
||||||
|
tower = "^0.4"
|
||||||
|
tower-http = { version = "^0.3", features = ["full"] }
|
||||||
|
tracing = "^0.1"
|
||||||
|
tracing-subscriber = "^0.3"
|
||||||
|
|
||||||
|
[dependencies.sea-orm]
|
||||||
|
version = "^0.9.2" # sea-orm version
|
||||||
|
features = [
|
||||||
|
"debug-print",
|
||||||
|
"runtime-tokio-native-tls",
|
||||||
|
"sqlx-sqlite",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
142
backend/api/src/lib.rs
Normal file
142
backend/api/src/lib.rs
Normal file
@@ -0,0 +1,142 @@
|
|||||||
|
use axum::{
|
||||||
|
http::{HeaderValue, Method},
|
||||||
|
response::IntoResponse,
|
||||||
|
routing::get,
|
||||||
|
Json, Router,
|
||||||
|
};
|
||||||
|
use axum_extra::routing::SpaRouter;
|
||||||
|
use clap::Parser;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::net::{IpAddr, Ipv6Addr, SocketAddr};
|
||||||
|
use std::str::FromStr;
|
||||||
|
use tower::ServiceBuilder;
|
||||||
|
use tower_http::cors::CorsLayer;
|
||||||
|
use tower_http::trace::TraceLayer;
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize, Debug)]
|
||||||
|
struct Docs {
|
||||||
|
key: String,
|
||||||
|
title: String,
|
||||||
|
first_publish_year: Option<u32>,
|
||||||
|
number_of_pages_median: Option<u32>,
|
||||||
|
isbn: Option<Vec<String>>,
|
||||||
|
cover_i: Option<u32>,
|
||||||
|
cover_url: Option<String>,
|
||||||
|
author_name: Option<Vec<String>>,
|
||||||
|
person: Option<Vec<String>>,
|
||||||
|
place: Option<Vec<String>>,
|
||||||
|
subject: 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)]
|
||||||
|
struct Books {
|
||||||
|
num_found: u32,
|
||||||
|
docs: Vec<Docs>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Books {
|
||||||
|
fn set_all_cover_urls(&mut self) {
|
||||||
|
for book in self.docs.iter_mut() {
|
||||||
|
match book.cover_i {
|
||||||
|
Some(cover_i) => {
|
||||||
|
book.cover_url = Some(format!(
|
||||||
|
"https://covers.openlibrary.org/b/id/{}-L.jpg",
|
||||||
|
cover_i
|
||||||
|
))
|
||||||
|
}
|
||||||
|
None => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup the command line interface with clap.
|
||||||
|
#[derive(Parser, Debug)]
|
||||||
|
#[clap(name = "server", about = "A server for our wasm project!")]
|
||||||
|
struct Opt {
|
||||||
|
/// set the log level
|
||||||
|
#[clap(short = 'l', long = "log", default_value = "debug")]
|
||||||
|
log_level: String,
|
||||||
|
|
||||||
|
/// set the listen addr
|
||||||
|
#[clap(short = 'a', long = "addr", default_value = "::1")]
|
||||||
|
addr: String,
|
||||||
|
|
||||||
|
/// set the listen port
|
||||||
|
#[clap(short = 'p', long = "port", default_value = "8081")]
|
||||||
|
port: u16,
|
||||||
|
|
||||||
|
/// set the directory where static files are to be found
|
||||||
|
#[clap(long = "static-dir", default_value = "../dist")]
|
||||||
|
static_dir: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
pub async fn main() {
|
||||||
|
let opt = Opt::parse();
|
||||||
|
|
||||||
|
// Setup logging & RUST_LOG from args
|
||||||
|
if std::env::var("RUST_LOG").is_err() {
|
||||||
|
std::env::set_var("RUST_LOG", format!("{},hyper=info,mio=info", opt.log_level))
|
||||||
|
}
|
||||||
|
// enable console logging
|
||||||
|
tracing_subscriber::fmt::init();
|
||||||
|
|
||||||
|
let app = Router::new()
|
||||||
|
.route("/api/hello", get(hello))
|
||||||
|
.merge(SpaRouter::new("/assets", opt.static_dir))
|
||||||
|
.layer(ServiceBuilder::new().layer(TraceLayer::new_for_http()))
|
||||||
|
.layer(
|
||||||
|
// see https://docs.rs/tower-http/latest/tower_http/cors/index.html
|
||||||
|
// for more details
|
||||||
|
//
|
||||||
|
// pay attention that for some request types like posting content-type: application/json
|
||||||
|
// it is required to add ".allow_headers([http::header::CONTENT_TYPE])"
|
||||||
|
// or see this issue https://github.com/tokio-rs/axum/issues/849
|
||||||
|
CorsLayer::new()
|
||||||
|
.allow_origin("http://localhost:8080".parse::<HeaderValue>().unwrap())
|
||||||
|
.allow_methods([Method::GET]),
|
||||||
|
);
|
||||||
|
|
||||||
|
let sock_addr = SocketAddr::from((
|
||||||
|
IpAddr::from_str(opt.addr.as_str()).unwrap_or(IpAddr::V6(Ipv6Addr::LOCALHOST)),
|
||||||
|
opt.port,
|
||||||
|
));
|
||||||
|
|
||||||
|
log::info!("listening on http://{}", sock_addr);
|
||||||
|
|
||||||
|
axum::Server::bind(&sock_addr)
|
||||||
|
.serve(app.into_make_service())
|
||||||
|
.await
|
||||||
|
.expect("Unable to start server");
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn hello(
|
||||||
|
axum::extract::Query(params): axum::extract::Query<HashMap<String, String>>,
|
||||||
|
) -> impl IntoResponse {
|
||||||
|
print!("Get items with query params: {:?}\n", params);
|
||||||
|
let search = params.get("search").unwrap();
|
||||||
|
let query = format!("https://openlibrary.org/search.json?q={}", search);
|
||||||
|
let res = reqwest::get(query).await.expect("Unable to request");
|
||||||
|
let mut resjson = res.json::<Books>().await.expect("Unable to return value");
|
||||||
|
resjson.docs.truncate(10);
|
||||||
|
resjson.set_all_cover_urls();
|
||||||
|
print!("Search token {:?}\n", search);
|
||||||
|
return Json(resjson);
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
//! SeaORM Entity. Generated by sea-orm-codegen 0.9.2
|
//! SeaORM Entity. Generated by sea-orm-codegen 0.9.3
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
@@ -33,6 +33,8 @@ pub enum Relation {
|
|||||||
BookSubject,
|
BookSubject,
|
||||||
#[sea_orm(has_many = "super::book_time::Entity")]
|
#[sea_orm(has_many = "super::book_time::Entity")]
|
||||||
BookTime,
|
BookTime,
|
||||||
|
#[sea_orm(has_many = "super::book_isbn::Entity")]
|
||||||
|
BookIsbn,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Related<super::book_author::Entity> for Entity {
|
impl Related<super::book_author::Entity> for Entity {
|
||||||
@@ -65,4 +67,10 @@ impl Related<super::book_time::Entity> for Entity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Related<super::book_isbn::Entity> for Entity {
|
||||||
|
fn to() -> RelationDef {
|
||||||
|
Relation::BookIsbn.def()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ActiveModelBehavior for ActiveModel {}
|
impl ActiveModelBehavior for ActiveModel {}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//! SeaORM Entity. Generated by sea-orm-codegen 0.9.2
|
//! SeaORM Entity. Generated by sea-orm-codegen 0.9.3
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
|
|||||||
32
backend/entity/src/entities/book_isbn.rs
Normal file
32
backend/entity/src/entities/book_isbn.rs
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
//! SeaORM Entity. Generated by sea-orm-codegen 0.9.3
|
||||||
|
|
||||||
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, DeriveEntityModel)]
|
||||||
|
#[sea_orm(table_name = "book_isbn")]
|
||||||
|
pub struct Model {
|
||||||
|
#[sea_orm(primary_key)]
|
||||||
|
pub id: i32,
|
||||||
|
pub isbn: String,
|
||||||
|
pub book_id: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||||
|
pub enum Relation {
|
||||||
|
#[sea_orm(
|
||||||
|
belongs_to = "super::book::Entity",
|
||||||
|
from = "Column::BookId",
|
||||||
|
to = "super::book::Column::Id",
|
||||||
|
on_update = "Cascade",
|
||||||
|
on_delete = "Cascade"
|
||||||
|
)]
|
||||||
|
Book,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Related<super::book::Entity> for Entity {
|
||||||
|
fn to() -> RelationDef {
|
||||||
|
Relation::Book.def()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ActiveModelBehavior for ActiveModel {}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
//! SeaORM Entity. Generated by sea-orm-codegen 0.9.2
|
//! SeaORM Entity. Generated by sea-orm-codegen 0.9.3
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//! SeaORM Entity. Generated by sea-orm-codegen 0.9.2
|
//! SeaORM Entity. Generated by sea-orm-codegen 0.9.3
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//! SeaORM Entity. Generated by sea-orm-codegen 0.9.2
|
//! SeaORM Entity. Generated by sea-orm-codegen 0.9.3
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//! SeaORM Entity. Generated by sea-orm-codegen 0.9.2
|
//! SeaORM Entity. Generated by sea-orm-codegen 0.9.3
|
||||||
|
|
||||||
use sea_orm::entity::prelude::*;
|
use sea_orm::entity::prelude::*;
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
//! SeaORM Entity. Generated by sea-orm-codegen 0.9.2
|
//! SeaORM Entity. Generated by sea-orm-codegen 0.9.3
|
||||||
|
|
||||||
pub mod prelude;
|
pub mod prelude;
|
||||||
|
|
||||||
pub mod book;
|
pub mod book;
|
||||||
pub mod book_author;
|
pub mod book_author;
|
||||||
|
pub mod book_isbn;
|
||||||
pub mod book_person;
|
pub mod book_person;
|
||||||
pub mod book_place;
|
pub mod book_place;
|
||||||
pub mod book_subject;
|
pub mod book_subject;
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
//! SeaORM Entity. Generated by sea-orm-codegen 0.9.2
|
//! SeaORM Entity. Generated by sea-orm-codegen 0.9.3
|
||||||
|
|
||||||
pub use super::book::Entity as Book;
|
pub use super::book::Entity as Book;
|
||||||
pub use super::book_author::Entity as BookAuthor;
|
pub use super::book_author::Entity as BookAuthor;
|
||||||
|
pub use super::book_isbn::Entity as BookIsbn;
|
||||||
pub use super::book_person::Entity as BookPerson;
|
pub use super::book_person::Entity as BookPerson;
|
||||||
pub use super::book_place::Entity as BookPlace;
|
pub use super::book_place::Entity as BookPlace;
|
||||||
pub use super::book_subject::Entity as BookSubject;
|
pub use super::book_subject::Entity as BookSubject;
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
mod entities;
|
pub mod entities;
|
||||||
pub use entities::*;
|
|
||||||
|
|
||||||
|
|||||||
@@ -38,32 +38,6 @@ impl MigrationTrait for Migration {
|
|||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
manager
|
|
||||||
.create_table(
|
|
||||||
Table::create()
|
|
||||||
.table(BookAuthor::Table)
|
|
||||||
.if_not_exists()
|
|
||||||
.col(
|
|
||||||
ColumnDef::new(BookAuthor::Id)
|
|
||||||
.integer()
|
|
||||||
.not_null()
|
|
||||||
.auto_increment()
|
|
||||||
.primary_key(),
|
|
||||||
)
|
|
||||||
.col(ColumnDef::new(BookAuthor::AuthorName).string().not_null())
|
|
||||||
.col(ColumnDef::new(BookAuthor::BookId).integer().not_null())
|
|
||||||
.foreign_key(
|
|
||||||
ForeignKey::create()
|
|
||||||
.name("FK_2e303c3a712662f1fc2a4d0aad6")
|
|
||||||
.from(BookAuthor::Table, BookAuthor::BookId)
|
|
||||||
.to(Book::Table, Book::Id)
|
|
||||||
.on_delete(ForeignKeyAction::Cascade)
|
|
||||||
.on_update(ForeignKeyAction::Cascade),
|
|
||||||
)
|
|
||||||
.to_owned(),
|
|
||||||
)
|
|
||||||
.await;
|
|
||||||
|
|
||||||
manager
|
manager
|
||||||
.create_table(
|
.create_table(
|
||||||
Table::create()
|
Table::create()
|
||||||
@@ -192,6 +166,32 @@ impl MigrationTrait for Migration {
|
|||||||
)
|
)
|
||||||
.to_owned(),
|
.to_owned(),
|
||||||
)
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
manager
|
||||||
|
.create_table(
|
||||||
|
Table::create()
|
||||||
|
.table(BookISBN::Table)
|
||||||
|
.if_not_exists()
|
||||||
|
.col(
|
||||||
|
ColumnDef::new(BookISBN::Id)
|
||||||
|
.integer()
|
||||||
|
.not_null()
|
||||||
|
.auto_increment()
|
||||||
|
.primary_key(),
|
||||||
|
)
|
||||||
|
.col(ColumnDef::new(BookISBN::ISBN).string().not_null())
|
||||||
|
.col(ColumnDef::new(BookISBN::BookId).integer().not_null())
|
||||||
|
.foreign_key(
|
||||||
|
ForeignKey::create()
|
||||||
|
.name("FK_2e303c3a712662f1fc2a4d0aae0")
|
||||||
|
.from(BookISBN::Table, BookISBN::BookId)
|
||||||
|
.to(Book::Table, Book::Id)
|
||||||
|
.on_delete(ForeignKeyAction::Cascade)
|
||||||
|
.on_update(ForeignKeyAction::Cascade),
|
||||||
|
)
|
||||||
|
.to_owned(),
|
||||||
|
)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,6 +216,9 @@ impl MigrationTrait for Migration {
|
|||||||
.await;
|
.await;
|
||||||
manager
|
manager
|
||||||
.drop_table(Table::drop().table(BookTime::Table).to_owned())
|
.drop_table(Table::drop().table(BookTime::Table).to_owned())
|
||||||
|
.await;
|
||||||
|
manager
|
||||||
|
.drop_table(Table::drop().table(BookISBN::Table).to_owned())
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -235,6 +238,7 @@ enum Book {
|
|||||||
//Place,
|
//Place,
|
||||||
//Subject,
|
//Subject,
|
||||||
//Time,
|
//Time,
|
||||||
|
//ISBN,
|
||||||
GoodreadId,
|
GoodreadId,
|
||||||
Description,
|
Description,
|
||||||
Cover,
|
Cover,
|
||||||
@@ -283,3 +287,11 @@ enum BookTime {
|
|||||||
Time,
|
Time,
|
||||||
BookId,
|
BookId,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Iden)]
|
||||||
|
enum BookISBN {
|
||||||
|
Table,
|
||||||
|
Id,
|
||||||
|
ISBN,
|
||||||
|
BookId,
|
||||||
|
}
|
||||||
|
|||||||
18
backend/orm/Cargo.toml
Normal file
18
backend/orm/Cargo.toml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
[package]
|
||||||
|
name = "booksman-orm"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
publish = false
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
serde = { version = "1", features = ["derive"] }
|
||||||
|
entity = { path = "../entity" }
|
||||||
|
chrono = "0.4"
|
||||||
|
|
||||||
|
[dependencies.sea-orm]
|
||||||
|
version = "^0.9.2" # sea-orm version
|
||||||
|
features = [
|
||||||
|
"debug-print",
|
||||||
|
"runtime-tokio-native-tls",
|
||||||
|
"sqlx-sqlite",
|
||||||
|
]
|
||||||
7
backend/orm/src/lib.rs
Normal file
7
backend/orm/src/lib.rs
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
mod mutation;
|
||||||
|
mod query;
|
||||||
|
|
||||||
|
pub use mutation::*;
|
||||||
|
pub use query::*;
|
||||||
|
|
||||||
|
pub use sea_orm;
|
||||||
55
backend/orm/src/mutation.rs
Normal file
55
backend/orm/src/mutation.rs
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
//use ::entity::entities::prelude::Book;
|
||||||
|
//use ::entity::entities::{prelude::*, *};
|
||||||
|
use sea_orm::*;
|
||||||
|
//use ::entity::entities::prelude::Book;
|
||||||
|
|
||||||
|
pub struct Mutation;
|
||||||
|
|
||||||
|
impl Mutation {
|
||||||
|
/* pub async fn create_post(
|
||||||
|
db: &DbConn,
|
||||||
|
form_data: post::Model,
|
||||||
|
) -> Result<post::ActiveModel, DbErr> {
|
||||||
|
post::ActiveModel {
|
||||||
|
title: Set(form_data.title.to_owned()),
|
||||||
|
text: Set(form_data.text.to_owned()),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
.save(db)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn update_post_by_id(
|
||||||
|
db: &DbConn,
|
||||||
|
id: i32,
|
||||||
|
form_data: post::Model,
|
||||||
|
) -> Result<post::Model, DbErr> {
|
||||||
|
let post: post::ActiveModel = Post::find_by_id(id)
|
||||||
|
.one(db)
|
||||||
|
.await?
|
||||||
|
.ok_or(DbErr::Custom("Cannot find post.".to_owned()))
|
||||||
|
.map(Into::into)?;
|
||||||
|
|
||||||
|
post::ActiveModel {
|
||||||
|
id: post.id,
|
||||||
|
title: Set(form_data.title.to_owned()),
|
||||||
|
text: Set(form_data.text.to_owned()),
|
||||||
|
}
|
||||||
|
.update(db)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn delete_post(db: &DbConn, id: i32) -> Result<DeleteResult, DbErr> {
|
||||||
|
let post: post::ActiveModel = Post::find_by_id(id)
|
||||||
|
.one(db)
|
||||||
|
.await?
|
||||||
|
.ok_or(DbErr::Custom("Cannot find post.".to_owned()))
|
||||||
|
.map(Into::into)?;
|
||||||
|
|
||||||
|
post.delete(db).await
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
/* pub async fn delete_all_books(db: &DbConn) -> Result<DeleteResult, DbErr> {
|
||||||
|
Book::delete_many().exec(db).await
|
||||||
|
} */
|
||||||
|
}
|
||||||
30
backend/orm/src/query.rs
Normal file
30
backend/orm/src/query.rs
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
use ::entity::entities::book::Entity as Book;
|
||||||
|
use ::entity::entities::book;
|
||||||
|
//use ::entity::entities::{prelude::*, *};
|
||||||
|
use sea_orm::*;
|
||||||
|
//use ::entity::entities::prelude::Book;
|
||||||
|
|
||||||
|
pub struct Query;
|
||||||
|
|
||||||
|
impl Query {
|
||||||
|
pub async fn find_book_by_id(db: &DbConn, id: i32) -> Result<Option<book::Model>, DbErr> {
|
||||||
|
Book::find_by_id(id).one(db).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If ok, returns (post models, num pages).
|
||||||
|
pub async fn find_posts_in_page(
|
||||||
|
db: &DbConn,
|
||||||
|
page: usize,
|
||||||
|
posts_per_page: usize,
|
||||||
|
) -> Result<(Vec<book::Model>, usize), DbErr> {
|
||||||
|
// Setup paginator
|
||||||
|
let paginator = Book::find()
|
||||||
|
.order_by_asc(book::Column::Id)
|
||||||
|
.paginate(db, posts_per_page);
|
||||||
|
let num_pages = paginator.num_pages().await?;
|
||||||
|
|
||||||
|
// Fetch paginated posts
|
||||||
|
paginator.fetch_page(page - 1).await.map(|p| (p, num_pages))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,158 +1,4 @@
|
|||||||
use axum::{
|
fn main() {
|
||||||
http::{HeaderValue, Method},
|
booksman_api::main();
|
||||||
response::IntoResponse,
|
|
||||||
routing::get,
|
|
||||||
Json, Router,
|
|
||||||
};
|
|
||||||
use axum_extra::routing::SpaRouter;
|
|
||||||
use clap::Parser;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::net::{IpAddr, Ipv6Addr, SocketAddr};
|
|
||||||
use std::str::FromStr;
|
|
||||||
use tower::ServiceBuilder;
|
|
||||||
use tower_http::cors::CorsLayer;
|
|
||||||
use tower_http::trace::TraceLayer;
|
|
||||||
|
|
||||||
#[derive(Deserialize, Serialize, Debug)]
|
|
||||||
struct Docs {
|
|
||||||
key: String,
|
|
||||||
title: String,
|
|
||||||
first_publish_year: Option<u32>,
|
|
||||||
number_of_pages_median: Option<u32>,
|
|
||||||
isbn: Option<Vec<String>>,
|
|
||||||
cover_i: Option<u32>,
|
|
||||||
cover_url: Option<String>,
|
|
||||||
author_name: Option<Vec<String>>,
|
|
||||||
person: Option<Vec<String>>,
|
|
||||||
place: Option<Vec<String>>,
|
|
||||||
subject: 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)]
|
|
||||||
struct Books {
|
|
||||||
num_found: u32,
|
|
||||||
docs: Vec<Docs>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Books {
|
|
||||||
fn set_all_cover_urls(&mut self) {
|
|
||||||
for book in self.docs.iter_mut() {
|
|
||||||
match book.cover_i {
|
|
||||||
Some(cover_i) => {
|
|
||||||
book.cover_url = Some(format!(
|
|
||||||
"https://covers.openlibrary.org/b/id/{}-L.jpg",
|
|
||||||
cover_i
|
|
||||||
))
|
|
||||||
}
|
|
||||||
None => (),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup the command line interface with clap.
|
|
||||||
#[derive(Parser, Debug)]
|
|
||||||
#[clap(name = "server", about = "A server for our wasm project!")]
|
|
||||||
struct Opt {
|
|
||||||
/// set the log level
|
|
||||||
#[clap(short = 'l', long = "log", default_value = "debug")]
|
|
||||||
log_level: String,
|
|
||||||
|
|
||||||
/// set the listen addr
|
|
||||||
#[clap(short = 'a', long = "addr", default_value = "::1")]
|
|
||||||
addr: String,
|
|
||||||
|
|
||||||
/// set the listen port
|
|
||||||
#[clap(short = 'p', long = "port", default_value = "8081")]
|
|
||||||
port: u16,
|
|
||||||
|
|
||||||
/// set the directory where static files are to be found
|
|
||||||
#[clap(long = "static-dir", default_value = "../dist")]
|
|
||||||
static_dir: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::main]
|
|
||||||
async fn main() {
|
|
||||||
let opt = Opt::parse();
|
|
||||||
|
|
||||||
// Setup logging & RUST_LOG from args
|
|
||||||
if std::env::var("RUST_LOG").is_err() {
|
|
||||||
std::env::set_var("RUST_LOG", format!("{},hyper=info,mio=info", opt.log_level))
|
|
||||||
}
|
|
||||||
// enable console logging
|
|
||||||
tracing_subscriber::fmt::init();
|
|
||||||
|
|
||||||
let app = Router::new()
|
|
||||||
.route("/api/hello", get(hello))
|
|
||||||
.merge(SpaRouter::new("/assets", opt.static_dir))
|
|
||||||
.layer(ServiceBuilder::new().layer(TraceLayer::new_for_http()))
|
|
||||||
.layer(
|
|
||||||
// see https://docs.rs/tower-http/latest/tower_http/cors/index.html
|
|
||||||
// for more details
|
|
||||||
//
|
|
||||||
// pay attention that for some request types like posting content-type: application/json
|
|
||||||
// it is required to add ".allow_headers([http::header::CONTENT_TYPE])"
|
|
||||||
// or see this issue https://github.com/tokio-rs/axum/issues/849
|
|
||||||
CorsLayer::new()
|
|
||||||
.allow_origin("http://localhost:8080".parse::<HeaderValue>().unwrap())
|
|
||||||
.allow_methods([Method::GET]),
|
|
||||||
);
|
|
||||||
|
|
||||||
let sock_addr = SocketAddr::from((
|
|
||||||
IpAddr::from_str(opt.addr.as_str()).unwrap_or(IpAddr::V6(Ipv6Addr::LOCALHOST)),
|
|
||||||
opt.port,
|
|
||||||
));
|
|
||||||
|
|
||||||
log::info!("listening on http://{}", sock_addr);
|
|
||||||
|
|
||||||
axum::Server::bind(&sock_addr)
|
|
||||||
.serve(app.into_make_service())
|
|
||||||
.await
|
|
||||||
.expect("Unable to start server");
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn hello(
|
|
||||||
axum::extract::Query(params): axum::extract::Query<HashMap<String, String>>,
|
|
||||||
) -> impl IntoResponse {
|
|
||||||
//"hello from server!"
|
|
||||||
//let res = reqwest::get("https://openlibrary.org/search.json?q=the+lord+of+the+rings")
|
|
||||||
// .await
|
|
||||||
// .expect("Unable to request");
|
|
||||||
//let resjson = res.json::<Books>().await.expect("Unable to return value");
|
|
||||||
print!("Get items with query params: {:?}\n", params);
|
|
||||||
//let search = params.get("search");
|
|
||||||
//let search = "";
|
|
||||||
let search = params.get("search").unwrap();
|
|
||||||
//match search {
|
|
||||||
// Some(token) => (),
|
|
||||||
// None => return "None",
|
|
||||||
//}
|
|
||||||
//let search = match params.get("search") {
|
|
||||||
// Some(&token) => token,
|
|
||||||
// _ => String(""),
|
|
||||||
//};
|
|
||||||
let query = format!("https://openlibrary.org/search.json?q={}", search);
|
|
||||||
let res = reqwest::get(query).await.expect("Unable to request");
|
|
||||||
let mut resjson = res.json::<Books>().await.expect("Unable to return value");
|
|
||||||
resjson.docs.truncate(10);
|
|
||||||
resjson.set_all_cover_urls();
|
|
||||||
print!("Search token {:?}\n", search);
|
|
||||||
return Json(resjson);
|
|
||||||
//return "Hello";
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user