Sanford Pun 5143307b3e
Demonstrate how to mock test SeaORM by separating core implementation from the web API (#890)
* Move core implementations to a standalone crate

* Set up integration test skeleton in `core`

* Demonstrate mock testing with query

* Move Rocket api code to a standalone crate

* Add mock execution

* Add MyDataMyConsent in COMMUNITY.md (#889)

* Add MyDataMyConsent in COMMUNITY.md

* Update MyDataMyConsent description in COMMUNITY.md

* Update COMMUNITY.md

Chronological order

* [cli] bump sea-schema to 0.9.3 (SeaQL/sea-orm#876)

* Update CHNAGELOG PR links

* 0.9.1 CHANGELOG

* Auto discover and run all issues & examples CI (#903)

* Auto discover and run all [issues] CI

* Auto discover and run all examples CI

* Fixup

* Testing

* Test [issues]

* Compile prepare_mock_db() conditionally based on "mock" feature

* Update workflow job to run mock test if `core` folder exists

* Update Actix3 example

* Fix merge conflict human error

* Update usize used in paginate to u64 (PR#789)

* Update sea-orm version in the Rocket example to 0.10.0

* Fix GitHub workflow to run mock test for core crates

* Increase the robustness of core crate check by verifying that the `core` folder is a crate

* Update Actix(4) example

* Update Axum example

* Update GraphQL example

* Update Jsonrpsee example

* Update Poem example

* Update Tonic example

* Cargo fmt

* Update Salvo example

* Update path of core/Cargo.toml in README.md

* Add mock test instruction in README.md

* Refactoring

* Fix Rocket examples

Co-authored-by: Amit Goyani <63532626+itsAmitGoyani@users.noreply.github.com>
Co-authored-by: Billy Chan <ccw.billy.123@gmail.com>
2022-09-23 12:57:43 +08:00

144 lines
3.8 KiB
Rust

use tonic::transport::Server;
use tonic::{Request, Response, Status};
use entity::post;
use migration::{Migrator, MigratorTrait};
use tonic_example_core::{
sea_orm::{Database, DatabaseConnection},
Mutation, Query,
};
use std::env;
pub mod post_mod {
tonic::include_proto!("post");
}
use post_mod::{
blogpost_server::{Blogpost, BlogpostServer},
Post, PostId, PostList, PostPerPage, ProcessStatus,
};
impl Post {
fn into_model(self) -> post::Model {
post::Model {
id: self.id,
title: self.title,
text: self.content,
}
}
}
#[derive(Default)]
pub struct MyServer {
connection: DatabaseConnection,
}
#[tonic::async_trait]
impl Blogpost for MyServer {
async fn get_posts(&self, request: Request<PostPerPage>) -> Result<Response<PostList>, Status> {
let conn = &self.connection;
let posts_per_page = request.into_inner().per_page;
let mut response = PostList { post: Vec::new() };
let (posts, _) = Query::find_posts_in_page(conn, 1, posts_per_page)
.await
.expect("Cannot find posts in page");
for post in posts {
response.post.push(Post {
id: post.id,
title: post.title,
content: post.text,
});
}
Ok(Response::new(response))
}
async fn add_post(&self, request: Request<Post>) -> Result<Response<PostId>, Status> {
let conn = &self.connection;
let input = request.into_inner().into_model();
let inserted = Mutation::create_post(conn, input)
.await
.expect("could not insert post");
let response = PostId {
id: inserted.id.unwrap(),
};
Ok(Response::new(response))
}
async fn update_post(&self, request: Request<Post>) -> Result<Response<ProcessStatus>, Status> {
let conn = &self.connection;
let input = request.into_inner().into_model();
match Mutation::update_post_by_id(conn, input.id, input).await {
Ok(_) => Ok(Response::new(ProcessStatus { success: true })),
Err(_) => Ok(Response::new(ProcessStatus { success: false })),
}
}
async fn delete_post(
&self,
request: Request<PostId>,
) -> Result<Response<ProcessStatus>, Status> {
let conn = &self.connection;
let id = request.into_inner().id;
match Mutation::delete_post(conn, id).await {
Ok(_) => Ok(Response::new(ProcessStatus { success: true })),
Err(_) => Ok(Response::new(ProcessStatus { success: false })),
}
}
async fn get_post_by_id(&self, request: Request<PostId>) -> Result<Response<Post>, Status> {
let conn = &self.connection;
let id = request.into_inner().id;
if let Some(post) = Query::find_post_by_id(conn, id).await.ok().flatten() {
Ok(Response::new(Post {
id,
title: post.title,
content: post.text,
}))
} else {
Err(Status::new(
tonic::Code::Aborted,
"Could not find post with id ".to_owned() + &id.to_string(),
))
}
}
}
#[tokio::main]
async fn start() -> Result<(), Box<dyn std::error::Error>> {
let addr = "0.0.0.0:50051".parse()?;
let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
// establish database connection
let connection = Database::connect(&database_url).await?;
Migrator::up(&connection, None).await?;
let hello_server = MyServer { connection };
Server::builder()
.add_service(BlogpostServer::new(hello_server))
.serve(addr)
.await?;
Ok(())
}
pub fn main() {
let result = start();
if let Some(err) = result.err() {
println!("Error: {}", err);
}
}