Как вставить HashMap в PostgreSQL как JSON тип? - PullRequest
2 голосов
/ 23 января 2020

contacts имеет структуру данных как HashMap, я использую PostgreSQL client - rust- postgres, чтобы вставить ключ и значение contact в таблицу, затем Я хочу выбрать из таблицы. Ниже то, что я пробовал до сих пор. Мне нужна помощь в написании правильного синтаксиса.

use postgres::{Client, NoTls};
use std::collections::HashMap;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut client = Client::connect("host=127.0.0.1 user=postgres", NoTls)?;

    client.simple_query("
        DROP TABLE 
        IF EXISTS following_relation;
        ")?;

    client.simple_query("
        CREATE TABLE following_relation (
            id               SERIAL NOT NULL PRIMARY KEY,
            relation         JSON NOT NULL
        )
    ")?;

    let mut contacts = HashMap::new();
    let mut v: Vec<String> = Vec::new();

    v = vec!["jump".to_owned(), "jog".to_string()];
    contacts.insert("Ashley", v.clone());

    for (name, hobby) in contacts.iter() {
        // 1. How to write sql statement with parameters?
        client.execute(
        "INSERT INTO following_relation(relation) 
         VALUE ('{"name" : $1, "hobby" : $2}')", 
        &[&name, &hobby],
    )?;  
    }

    for row in client.query("SELECT id, relation FROM following_relation", &[])? {
        // 2. How to read from parse the result?
        let id: i32 = row.get(0);
        let relation = row.get(1);
        //println!("found person: {} {} {:?}", id, relation["name"], relation["hobby"]); 
    }
    Ok(())
}

Мне подсказали

  1. Как и в сообщении об ошибке, ваш запрос имеет значение VALUE, но ему нужно быть значениями.
  2. Параметры запроса нельзя интерполировать в строки. Вы должны построить объект в Rust и использовать https://docs.rs/postgres/0.17.0/postgres/types/struct.Json.html для переноса типов при вставке.

Я понятия не имею, как применить pub struct Json<T>(pub T); здесь.

Как построить query, необходимый для функции execute?

pub fn execute<T: ?Sized>(
    &mut self,
    query: &T,
    params: &[&(dyn ToSql + Sync)]
) -> Result<u64, Error>
where
    T: ToStatement, 

ОБНОВЛЕНО, я попытался с более кратким примером кода

use postgres::{Client, NoTls};
use postgres::types::Json;
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
struct relations {
    name : String,
    hobby: Vec<String>
}
pub struct Json<T>(pub T);

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut client = Client::connect("host=127.0.0.1 user=postgres", NoTls)?;

    client.simple_query("
        DROP TABLE 
        IF EXISTS following_relation;

        ")?;

    client.simple_query("
        CREATE TABLE following_relation (
            id      SERIAL PRIMARY KEY,
            relation    JSON NOT NULL
        )
    ")?;

    let rel = relations {
        name: "czfzdxx".to_string(),
        hobby: vec![
            "basketball".to_string(),
            "jogging".to_string()
        ],
    };

    client.execute(
        r#"INSERT INTO following_relation(relation)
             VALUE ($1)"#,
        &[&Json(&rel)]
    )?;

    Ok(())
}

Я получаю

error[E0432]: unresolved import `postgres::types::Json`

Ответы [ 2 ]

5 голосов
/ 23 января 2020

Вы хотите Rust необработанный строковый литерал :

for (name, hobby) in contacts.iter() {
    client.execute(
        r#"INSERT INTO following_relation(relation) 
           VALUE ('{"name" : ($1), "hobby" : ($2)}')"#,
        &[&name, &following],
    )?;
}

Между началом r#" и концом "# ваши строковые литералы могут иметь любой символ, кроме самого # без побега. Если вам также нужен сам #, тогда необработанные строковые литералы начинаются с нескольких # с и заканчиваются соответствующим числом # с.

1 голос
/ 29 января 2020

Вот main.rs:

use postgres::{Client, NoTls};
use serde::{Deserialize, Serialize};
use postgres_types::Json;
use postgres_types::{FromSql};


#[derive(Debug, Deserialize, Serialize, FromSql)]
struct Relation {
    name : String,
    hobby: Vec<String>
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut client = Client::connect("host=127.0.0.1 user=postgres", NoTls)?;

    client.simple_query("
        DROP TABLE 
        IF EXISTS following_relation;

        ")?;

    client.simple_query("
        CREATE TABLE following_relation (
            id      SERIAL PRIMARY KEY,
            relation    JSON NOT NULL
        )
    ")?;

    let rel = Relation {
        name: "czfzdxx".to_string(),
        hobby: vec![
            "basketball".to_string(),
            "jogging".to_string()
        ],
    };

    client.execute(
        "INSERT INTO following_relation (relation) VALUES ($1)",
        &[&Json::<Relation>(rel)]
    )?;

    for row in &client.query("SELECT relation FROM following_relation", &[]).unwrap() {
        let rel: Json<Relation> = row.get(0);
        println!("{:?}", rel);
    }

    Ok(())
}

и Cargo.toml:

[package]
name = "testapp"
version = "0.1.0"
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
postgres = {version = "0.17.0"}
tokio-postgres = "0.5.1"
serde = {version = "1.0.104", features = ["derive"]}
postgres-types = {version = "0.1.0", features = ["derive", "with-serde_json-1"]}
serde_json = "1.0.45"

А вот соответствующая используемая документация: postgres_types и postgres. Для этого стороннего типа реализован поиск признаков serde_json, ToSql и FromSql.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...