簡體   English   中英

如何從 Rust 的閉包中返回 tokio_postgres ToSql 類型?

[英]How to return tokio_postgres ToSql type from closure in Rust?

我如何通過將ToSql數據作為閉包傳遞來避免重復自己,告訴 tokio-postgres 哪些數據列,從我的各種結構模型到COPY / SELECT /etc?

例如,理想情況下,我可以傳遞各種表/列參數,例如:

// see MRE, "copy_in" performs boilerplate to copy binary format in postgres table
copy_in(
    &mut client, // the postgres client setup in tokio
    "table_name", // meta info about what table/columns to insert
    &["col1", "col2", "col3", "col4"],
    &vec![Type::INT4, Type::VARCHAR, Type::INT4, Type::INT4],
    &rows_of_struct_data, // the vec of data I plan to insert
    // then here's the hard part: which fields to extract from each row... (not works)
    |m| &[&[&m.id], &[&m.name], &[&m.range_begin, &m.range_end]] as &[&[&(dyn ToSql + Sync)]]
  );

tokio_postgres需要一種用於在復制期間寫入二進制數據的類型Vec<&(dyn ToSql + Sync)> ,雖然硬編碼什么被push ed 到 Vec 是有效的,但我很困惑如何傳遞一個動態決定要push什么的參數它。

我對此有兩個想法,但推薦的方法是什么?

  1. 如這個MRE所示,我可以將一個閉包傳遞給我的復制函數,該函數返回每行要寫入標准輸入的哪些列,但是如何鍵入閉包以避免?:

預期&dyn ToSql + Sync ,找到 trait 對象dyn ToSql

  1. 或者,如此MRE所示,我可以將Vec傳遞給我的閉包,以便它為每一行推送列數據,但這有幾個生命周期問題,例如:

row的引用在此處轉義異步閉包主體

在我的兩種方法中,我終於得到了 #1 的工作,盡管我不接受我自己的答案,以防出現更好的建議。

這是工作的MRE

這是我的理解中缺少的內容:

  • 我需要為每種類型的列返回一個 Vec,否則如果單個 Vec 同時包含i32String ,則違反ToSql類型
  • 我需要返回一個擁有的對象不是一個引用,因為 Rust 中的函數不能返回它們擁有的引用。

有興趣了解純函數式編程學習其他人可能會推薦的內容。 這對理解如何使用閉包非常有幫助。 #2 方法有終身挑戰,如果其他人對此有見解,我很感興趣。

我不知道如何返回 tokio_postgres &dyn ToSql + Sync 類型。 但是我在下面通過這種方式解決了這個問題。 我正在使用 postgres 的二進制副本插入數據。

桌子:

CREATE TABLE IF NOT EXISTS test (
    id SERIAL PRIMARY KEY,
    name VARCHAR NOT NULL
)

為了填充表格,我使用:

use tokio_postgres::types::{Type, ToSql};
use tokio_postgres::binary_copy::BinaryCopyInWriter;
use tokio_postgres::{NoTls, Error};
use futures::{pin_mut};

async fn main() -> Result<(), Error> {

    //...

    let config = format!("host={} user={} password='{}' dbname={} port={} connect_timeout=10",host, user, passwd, dbname, port);
    let (client, connection) = tokio_postgres::connect(&config, NoTls).await?;

    tokio::spawn(async move {
        if let Err(e) = connection.await {
            eprintln!("Connection error: {}", e);
        }
    });

    let data: Vec<(i32,&str)> = vec![(1i32,"hello,"),
        (2i32,"world!"),
        (3i32,"how"),
        (4i32,"are"),
        (5i32,"you"),
        (6i32,"today?")];

    let sink = client
        .copy_in("COPY test (id, name) FROM STDIN BINARY")
        .await
        .unwrap();

    let writer = BinaryCopyInWriter::new(sink, &[Type::INT4, Type::VARCHAR]);
    pin_mut!(writer);

    for i in 0..data.len() {
        let (id, name) = data[i];
        writer.as_mut().write(&[&id, &name]).await.unwrap();
    }

    writer.finish().await?;
    Ok(())
}

我使用元組來存儲數據,然后我解包元組以將數據插入數據庫。 依賴項是 tokio-postgres = "0.7.6", tokio = { version = "1.20.0", features = ["full"] } 和 futures = "0.3"。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM