Types 如何创建同时接受sqlx数据库池和事务的actix web服务器?

Types 如何创建同时接受sqlx数据库池和事务的actix web服务器?,types,rust,lifetime,actix-web,rust-sqlx,Types,Rust,Lifetime,Actix Web,Rust Sqlx,我正在尝试使用和设置一个web应用程序,在这里我可以进行具有自己的web服务器和数据库事务的测试。我已经尝试设置我的服务器创建,以便它接受数据库(Postgres)池或使用trait的事务。尽管我在编译应用程序代码和测试时遇到了一些问题: //main.rs 使用std::net::TcpListener; 使用actix_web::dev::Server; 使用actix_web::{web,App,HttpServer,Responder}; 使用sqlx::PgPool; 异步fn创建_p

我正在尝试使用和设置一个web应用程序,在这里我可以进行具有自己的web服务器和数据库事务的测试。我已经尝试设置我的服务器创建,以便它接受数据库(Postgres)池或使用trait的事务。尽管我在编译应用程序代码和测试时遇到了一些问题:

//main.rs
使用std::net::TcpListener;
使用actix_web::dev::Server;
使用actix_web::{web,App,HttpServer,Responder};
使用sqlx::PgPool;
异步fn创建_pool()->PgPool{
PgPool::connect(“postgres://postgres:postgres@本地主机:5432/postgres)
.等待
.expect(“创建池失败”)
}
异步fn index()->impl响应程序{
“你好,世界!”
}
发布fn创建_服务器(
听众:TcpListener,
池:E,
)->结果
哪里
E:sqlx::Executor`不满意
-->src\main.rs:37:29
|
17 |发布fn创建|服务器(
|------本节中的绑定要求
...
22 | E:sqlx::Executor`未为`Pool'实现`
|
=帮助:找到了以下实现:
+抄袭,
|----此绑定在“创建\u服务器”中需要`
...
37 |创建_服务器(侦听器,池)。展开()。等待
|^^^^^未为“池”实现特征“复制”`

试图对执行者特征进行泛化有点过火。 您可能应该在测试中使用大小为1的池,并手动调用
Begin
ROLLBACK

#[actix_rt::test]
async fn test_endpoint() {
    // build with only one connection
    let pool = PgPoolOptions::new()
        .max_connections(1)
        .connect("postgres://postgres:postgres@localhost:5432/postgres")
        .await
        .expect("pool failed");

    sqlx::query("BEGIN")
        .execute(&pool)
        .await
        .expect("BEGIN failed");
    let saved_pool = pool.clone();
    let listener = TcpListener::bind("0.0.0.0:0").expect("Failed to create listener");
    let server = HttpServer::new(move || 
    App::new().data(pool.clone()).service(one))
            .listen(listener)
            .expect("fail to bind")
            .run();
    tokio::spawn(server);

    // your test

    sqlx::query("ROLLBACK")
        .execute(&saved_pool)
        .await
        .expect("ROLLBACK failed");
}
这样,您不必更改代码来处理测试

// main.rs
use actix_web::{get, web, App, HttpServer, Responder};
use sqlx::{postgres::PgPool, Row};
use std::net::TcpListener;

#[get("/one")]
async fn one(pool: web::Data<PgPool>) -> impl Responder {
    let row = sqlx::query("select 1 as id")
        .fetch_one(pool.get_ref())
        .await
        .unwrap();
    let one: i32 = row.try_get("id").unwrap();
    format!("{:?}", one)
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    let pool = PgPool::connect("postgres://postgres:postgres@localhost:5432/postgres")
        .await
        .expect("Failed to create pool");
    const PORT: usize = 8088;
    let listener =
        TcpListener::bind(format!("0.0.0.0:{}", PORT)).expect("Failed to create listener");

    println!("Running on port {}", PORT);
    HttpServer::new(move || App::new().data(pool.clone()).service(one))
        .listen(listener)?
        .run()
        .await
}

#[cfg(test)]
pub mod tests {
    use super::*;
    use sqlx::postgres::PgPoolOptions;

    #[actix_rt::test]
    async fn test_endpoint() {
        // build with only one connection
        let pool = PgPoolOptions::new()
            .max_connections(1)
            .connect("postgres://postgres:postgres@localhost:5432/postgres")
            .await
            .expect("pool failed");

        sqlx::query("BEGIN")
            .execute(&pool)
            .await
            .expect("BEGIN failed");

        let saved_pool = pool.clone();

        let listener = TcpListener::bind("0.0.0.0:0").expect("Failed to create listener");
        let server = HttpServer::new(move || App::new().data(pool.clone()).service(one))
            .listen(listener)
            .expect("fail to bind")
            .run();
        tokio::spawn(server);

        // your test

        sqlx::query("ROLLBACK")
            .execute(&saved_pool)
            .await
            .expect("ROLLBACK failed");
    }

    #[actix_rt::test]
    async fn test_rollback() {
        let pool = PgPoolOptions::new()
            .max_connections(1)
            .connect("postgres://postgres:postgres@localhost:5432/postgres")
            .await
            .expect("pool failed");

        sqlx::query("BEGIN")
            .execute(&pool)
            .await
            .expect("BEGIN failed");

        sqlx::query("CREATE TABLE  IF NOT EXISTS test (id SERIAL, name TEXT)")
            .execute(&pool)
            .await
            .expect("CREATE TABLE test failed");

        sqlx::query("INSERT INTO test (name) VALUES ('bob')")
            .execute(&pool)
            .await
            .expect("INSERT test failed");

        let count: i64 = sqlx::query("SELECT COUNT(id) as count from test")
            .fetch_one(&pool)
            .await
            .expect("SELECT COUNT test failed")
            .try_get("count")
            .unwrap();
        sqlx::query("ROLLBACK")
            .execute(&pool)
            .await
            .expect("ROLLBACK failed");

        assert_eq!(count, 1);
    }

    #[actix_rt::test]
    async fn test_no_rollback() {
        let pool = PgPoolOptions::new()
            .max_connections(1)
            .connect("postgres://postgres:postgres@localhost:5432/postgres")
            .await
            .expect("pool failed");

        sqlx::query("CREATE TABLE  IF NOT EXISTS test2 (id SERIAL, name TEXT)")
            .execute(&pool)
            .await
            .expect("CREATE TABLE test failed");

        sqlx::query("INSERT INTO test2 (name) VALUES ('bob')")
            .execute(&pool)
            .await
            .expect("INSERT test failed");

        let count: i64 = sqlx::query("SELECT COUNT(id) as count from test2")
            .fetch_one(&pool)
            .await
            .expect("SELECT COUNT failed")
            .try_get("count")
            .unwrap();

        // this will failed the second time you run your test
        assert_eq!(count, 1);
    }
}
//main.rs
使用actix_web::{get,web,App,HttpServer,Responder};
使用sqlx::{postgres::PgPool,Row};
使用std::net::TcpListener;
#[获取(“/one”)]
异步fn-one(池:web::Data)->impl响应程序{
让row=sqlx::query(“选择1作为id”)
.fetch_one(pool.get_ref())
.等待
.unwrap();
让一个:i32=row.try_get(“id”).unwrap();
格式!(“{:?}”,一)
}
#[actix_web::main]
异步fn main()->std::io::Result{
让pool=PgPool::connect(“postgres://postgres:postgres@本地主机:5432/postgres)
.等待
.expect(“未能创建池”);
常数端口:usize=8088;
让听者=
TcpListener::bind(格式!(“0.0.0.0:{}”,端口)).expect(“未能创建侦听器”);
println!(“在端口{}上运行”,端口);
HttpServer::new(移动| | App::new().data(pool.clone()).service(一个))
.听(听众)?
.run()
.等待
}
#[cfg(测试)]
pub-mod测试{
使用超级::*;
使用sqlx::postgres::PgPoolOptions;
#[活动:测试]
异步fn测试_端点(){
//仅使用一个连接构建
let pool=PgPoolOptions::new()
.最大连接数(1)
.连接(“postgres://postgres:postgres@本地主机:5432/postgres)
.等待
.expect(“池失败”);
sqlx::查询(“开始”)
.execute(&pool)
.等待
.预期(“开始失败”);
让保存的_pool=pool.clone();
让listener=TcpListener::bind(“0.0.0.0:0”)。预期(“未能创建侦听器”);
让server=HttpServer::new(移动| | App::new().data(pool.clone()).service(一个))
.听(听众)
.预期(“未能绑定”)
.run();
tokio::spawn(服务器);
//你的测试
sqlx::查询(“回滚”)
.execute(保存的\u池(&U)
.等待
.expect(“回滚失败”);
}
#[活动:测试]
异步fn测试_回滚(){
let pool=PgPoolOptions::new()
.最大连接数(1)
.连接(“postgres://postgres:postgres@本地主机:5432/postgres)
.等待
.expect(“池失败”);
sqlx::查询(“开始”)
.execute(&pool)
.等待
.预期(“开始失败”);
sqlx::query(“如果不存在则创建表测试(id序列号,名称文本)”)
.execute(&pool)
.等待
.expect(“创建表测试失败”);
sqlx::query(“插入测试(名称)值('bob')”)
.execute(&pool)
.等待
.expect(“插入测试失败”);
let count:i64=sqlx::query(“选择count(id)作为测试中的计数”)
.fetch_one(&pool)
.等待
.expect(“选择计数测试失败”)
.试试看(“计数”)
.unwrap();
sqlx::查询(“回滚”)
.execute(&pool)
.等待
.expect(“回滚失败”);
断言(计数,1);
}
#[活动:测试]
异步fn测试\u否\u回滚(){
let pool=PgPoolOptions::new()
.最大连接数(1)
.连接(“postgres://postgres:postgres@本地主机:5432/postgres)
.等待
.expect(“池失败”);
sqlx::query(“如果不存在,则创建表test2(id序列号,名称文本)”)
.execute(&pool)
.等待
.expect(“创建表测试失败”);
sqlx::query(“插入到test2(名称)值('bob')”)
.execute(&pool)
.等待
.expect(“插入测试失败”);
let count:i64=sqlx::query(“从test2中选择count(id)作为count”)
.fetch_one(&pool)
.等待
.expect(“选择计数失败”)
.试试看(“计数”)
.unwrap();
//这将在您第二次运行测试时失败
断言(计数,1);
}
}

试图对执行者特征进行泛化有点过火。 您可能应该在测试中使用大小为1的池,并手动调用
Begin
ROLLBACK

#[actix_rt::test]
async fn test_endpoint() {
    // build with only one connection
    let pool = PgPoolOptions::new()
        .max_connections(1)
        .connect("postgres://postgres:postgres@localhost:5432/postgres")
        .await
        .expect("pool failed");

    sqlx::query("BEGIN")
        .execute(&pool)
        .await
        .expect("BEGIN failed");
    let saved_pool = pool.clone();
    let listener = TcpListener::bind("0.0.0.0:0").expect("Failed to create listener");
    let server = HttpServer::new(move || 
    App::new().data(pool.clone()).service(one))
            .listen(listener)
            .expect("fail to bind")
            .run();
    tokio::spawn(server);

    // your test

    sqlx::query("ROLLBACK")
        .execute(&saved_pool)
        .await
        .expect("ROLLBACK failed");
}
这样,您不必更改代码来处理测试

// main.rs
use actix_web::{get, web, App, HttpServer, Responder};
use sqlx::{postgres::PgPool, Row};
use std::net::TcpListener;

#[get("/one")]
async fn one(pool: web::Data<PgPool>) -> impl Responder {
    let row = sqlx::query("select 1 as id")
        .fetch_one(pool.get_ref())
        .await
        .unwrap();
    let one: i32 = row.try_get("id").unwrap();
    format!("{:?}", one)
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    let pool = PgPool::connect("postgres://postgres:postgres@localhost:5432/postgres")
        .await
        .expect("Failed to create pool");
    const PORT: usize = 8088;
    let listener =
        TcpListener::bind(format!("0.0.0.0:{}", PORT)).expect("Failed to create listener");

    println!("Running on port {}", PORT);
    HttpServer::new(move || App::new().data(pool.clone()).service(one))
        .listen(listener)?
        .run()
        .await
}

#[cfg(test)]
pub mod tests {
    use super::*;
    use sqlx::postgres::PgPoolOptions;

    #[actix_rt::test]
    async fn test_endpoint() {
        // build with only one connection
        let pool = PgPoolOptions::new()
            .max_connections(1)
            .connect("postgres://postgres:postgres@localhost:5432/postgres")
            .await
            .expect("pool failed");

        sqlx::query("BEGIN")
            .execute(&pool)
            .await
            .expect("BEGIN failed");

        let saved_pool = pool.clone();

        let listener = TcpListener::bind("0.0.0.0:0").expect("Failed to create listener");
        let server = HttpServer::new(move || App::new().data(pool.clone()).service(one))
            .listen(listener)
            .expect("fail to bind")
            .run();
        tokio::spawn(server);

        // your test

        sqlx::query("ROLLBACK")
            .execute(&saved_pool)
            .await
            .expect("ROLLBACK failed");
    }

    #[actix_rt::test]
    async fn test_rollback() {
        let pool = PgPoolOptions::new()
            .max_connections(1)
            .connect("postgres://postgres:postgres@localhost:5432/postgres")
            .await
            .expect("pool failed");

        sqlx::query("BEGIN")
            .execute(&pool)
            .await
            .expect("BEGIN failed");

        sqlx::query("CREATE TABLE  IF NOT EXISTS test (id SERIAL, name TEXT)")
            .execute(&pool)
            .await
            .expect("CREATE TABLE test failed");

        sqlx::query("INSERT INTO test (name) VALUES ('bob')")
            .execute(&pool)
            .await
            .expect("INSERT test failed");

        let count: i64 = sqlx::query("SELECT COUNT(id) as count from test")
            .fetch_one(&pool)
            .await
            .expect("SELECT COUNT test failed")
            .try_get("count")
            .unwrap();
        sqlx::query("ROLLBACK")
            .execute(&pool)
            .await
            .expect("ROLLBACK failed");

        assert_eq!(count, 1);
    }

    #[actix_rt::test]
    async fn test_no_rollback() {
        let pool = PgPoolOptions::new()
            .max_connections(1)
            .connect("postgres://postgres:postgres@localhost:5432/postgres")
            .await
            .expect("pool failed");

        sqlx::query("CREATE TABLE  IF NOT EXISTS test2 (id SERIAL, name TEXT)")
            .execute(&pool)
            .await
            .expect("CREATE TABLE test failed");

        sqlx::query("INSERT INTO test2 (name) VALUES ('bob')")
            .execute(&pool)
            .await
            .expect("INSERT test failed");

        let count: i64 = sqlx::query("SELECT COUNT(id) as count from test2")
            .fetch_one(&pool)
            .await
            .expect("SELECT COUNT failed")
            .try_get("count")
            .unwrap();

        // this will failed the second time you run your test
        assert_eq!(count, 1);
    }
}
//main.rs
使用actix_web::{get,web,App,HttpServer,Responder};
使用sqlx::{postgres::PgPool,Row};
使用std::net::TcpListener;
#[获取(“/一”)