Ver código fonte

WIP Postgres support

Postgres support part way in.  However, it does not support a
nice Map<String, Value> class to handle things easily without
defining a mapping struct in Rust.
master
Jonathan M. Altman 4 anos atrás
pai
commit
4ec318f3d7
3 arquivos alterados com 1246 adições e 347 exclusões
  1. +1056
    -280
      Cargo.lock
  2. +10
    -6
      Cargo.toml
  3. +180
    -61
      src/main.rs

+ 1056
- 280
Cargo.lock
Diferenças do arquivo suprimidas por serem muito extensas
Ver arquivo


+ 10
- 6
Cargo.toml Ver arquivo

@@ -7,13 +7,17 @@ edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
r2d2 = "0.8.5"
r2d2_sqlite = "0.12.0"
rusqlite = "0.20.0"
time = "0.1.42"
serde = "1.0.101"
chrono = "0.4"
r2d2 = "0.8.9"
r2d2_sqlite = "0.17.0"
rusqlite = {version="0.24.0", features=["chrono"]}
serde = {version="1.0.101", features=["derive"]}
serde_json = "1.0"
serde_rusqlite = "0.22.0"
serde_rusqlite = "0.26.0"
clap = "2.33.0"
failure = "0.1.6"
simple-error = "0.2.1"
postgres = {version="0.17.5", features=["with-chrono-0_4", "with-time-0_2"]}
r2d2_postgres = "0.16.0"
rpassword = "4.0.1"
serde_postgres = "0.2.0"

+ 180
- 61
src/main.rs Ver arquivo

@@ -3,100 +3,219 @@ extern crate r2d2;
extern crate r2d2_sqlite;
extern crate rusqlite;
extern crate simple_error;
extern crate rpassword;

use clap::{App, SubCommand};
//use std::fmt;
use clap::{App, AppSettings, SubCommand, Arg};
use chrono::prelude::Utc;
use r2d2::Pool;
use r2d2_sqlite::SqliteConnectionManager;
use rusqlite::params;
use postgres::{NoTls, Config};
use r2d2_sqlite::SqliteConnectionManager;
use r2d2_postgres::PostgresConnectionManager;
use serde_json::{Map, Value};
use serde_rusqlite::from_row;
use serde_rusqlite::Result as SRResult;
use serde_rusqlite::from_row as from_row_s;
use serde_rusqlite::Result as SRSResult;
use serde::Deserialize;
use std::error::Error;
// use serde_postgres::from_row as from_row_p;
// use serde_postgres::DeResult as SRPResult;
use simple_error::*;
use std::str::FromStr;

fn main() -> Result<(), SimpleError> {
fn main() -> Result<(), Box<dyn Error>> {
let matches = App::new("Rust DB Play")
.version("1.0")
.author("Jonathan Altman <jonathan@async.io>")
.about("Test out Rust database result serialization")
.setting(AppSettings::SubcommandRequiredElseHelp)
.subcommand(SubCommand::with_name("sqlite").about("Test on sqlite"))
.subcommand(SubCommand::with_name("postgres").about("Test on postgres"))
.subcommand(SubCommand::with_name("postgres").about("Test on postgres").arg(
Arg::with_name("dsn") // And their own arguments
.help("postgres dsn to connect to (password will be prompted for, and entered into DSN where {password} is")
.index(1)
.required(true),
),)
.get_matches();

return match matches.subcommand_name() {
Some("sqlite") => test_sqlite(),
Some("postgres") => test_postgres(),
Some("postgres") => {
let sub_matches = matches.subcommand_matches("postgres").unwrap();
let dsn_arg = sub_matches.value_of("dsn").unwrap();
test_postgres(dsn_arg)
},
None => bail!("No database specified"),
_ => bail!("Unknown database specified"),
};
}

fn test_postgres() -> Result<(), SimpleError> {
println!("Postgres: Not implemented yet");
return Ok(());
fn test_postgres(dsn_template: &str) -> Result<(), Box<dyn Error>> {
let dsn = match dsn_template.contains("{password}") {
true => {
let pass = rpassword::read_password_from_tty(Some("DB Password: ")).unwrap();
dsn_template.replace("{password}", &pass)
},
false => dsn_template.to_string()
};
let pg_config = Config::from_str(&dsn).unwrap();
let (pool, table_name) = setup_postgres(pg_config)?;
test_postgres_json(pool, &table_name)
}

fn test_sqlite() -> Result<(), SimpleError> {
let (pool, table_name) = setup_sqlite().unwrap();
return match test_sqlite_json(pool, &table_name) {
Ok(()) => Ok(()),
// @TODO (2019-11-19, Jonathan) Extract sqlite error here
Err(_) => bail!("Error in testing sqlite"),
};
}
fn setup_postgres(cfg: Config) -> Result<(Pool<PostgresConnectionManager<NoTls>>, String), SimpleError> {
fn setup_pool(cfg: Config) -> Pool<PostgresConnectionManager<NoTls>> {
let manager = PostgresConnectionManager::new(
cfg,
NoTls
);
let pool = Pool::new(manager).unwrap();
pool
}
fn setup_db_structure(pool: &Pool<PostgresConnectionManager<NoTls>>, table_name: &str) -> Result<u64, postgres::Error> {
let mut conn = pool.get().unwrap();

fn setup_sqlite() -> SRResult<(Pool<SqliteConnectionManager>, String)> {
fn setup_pool() -> Pool<SqliteConnectionManager> {
let manager = SqliteConnectionManager::memory();
let pool = Pool::new(manager).unwrap();
pool
}
fn setup_db_structure(pool: &Pool<SqliteConnectionManager>, table_name: &str) -> SRResult<()> {
let conn = pool.get().unwrap();
conn.execute(
format!(
"CREATE TABLE {} (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
time_created TEXT NOT NULL,
data BLOB,
data_null BLOB
)",
table_name
)
.as_str(),
params![],
format!("DROP TABLE IF EXISTS {0}", table_name).as_str(),
&[],
)?;

conn.execute(
"INSERT INTO person (name, time_created, data, data_null)
VALUES (?1, ?2, ?3, ?4)",
params![
"Steven".to_string(),
time::get_time(),
"This is some text".to_string(),
None as Option<Vec<u8>>
conn.execute(
format!(
"CREATE TABLE {0} (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
time_created TIMESTAMP WITH TIME ZONE NOT NULL,
data BYTEA,
data_null BYTEA
)",
table_name
)
.as_str(),
&[],
)?;

return conn.execute(
"INSERT INTO test_table (name, time_created, data, data_null)
VALUES ($1, $2, $3, $4)"
,
&[
&"Steven".to_string(),
&Utc::now(),
&"this is a string".as_bytes(),
&None::<&[u8]>,
],
)?;
Ok(())
);
}

const TABLE_NAME: &str = "test_table";
let pool = setup_pool(cfg);
if let Err(e) = setup_db_structure(&pool, &TABLE_NAME) {
bail!("{}", e.to_string())
}
println!("Done setting up db and checking error");

const TABLE_NAME: &str = "person";
let pool = setup_pool();
setup_db_structure(&pool, TABLE_NAME)?;
Ok((pool, TABLE_NAME.to_string()))
return Ok((pool, TABLE_NAME.to_string()));
}

fn test_sqlite_json(pool: Pool<SqliteConnectionManager>, table_name: &String) -> SRResult<()> {
let conn = pool.get().unwrap();
let mut stmt = conn.prepare(&format!("SELECT * FROM {}", table_name))?;
let result_iter = stmt.query_map(params![], |row| {
Ok(from_row::<Map<String, Value>>(row).unwrap())
})?;
for cur_result in result_iter {
#[derive(Clone, Debug, Deserialize)]
struct Person {
name: String,
}

fn test_postgres_json(pool: Pool<PostgresConnectionManager<NoTls>>, table_name: &String) -> Result<(), Box<dyn Error>> {
let mut conn = pool.get().unwrap();
let stmt = conn.prepare(&format!("SELECT name FROM {}", table_name)).unwrap();
let rows: Vec<postgres::Row> = conn.query(&stmt, &[])?;
for row in rows {
println!("Dumping a row...");
let person: Person = serde_postgres::from_row(&row)?;
dbg!(person);
let cur_result: Map<String, Value> = serde_postgres::from_row(&row)?;
println!(
"Found row {:?}",
serde_json::to_string(&cur_result.unwrap()).unwrap()
"Found row macro {:?}",
serde_json::json!(&cur_result).to_string()
);
}
/*
let cur_result: Vec<Map<String, Value>> = serde_postgres::from_rows(&rows)?;
println!(
"Found row macro {:?}",
serde_json::json!(&cur_result).to_string()
);
*/
Ok(())
}


fn test_sqlite() -> Result<(), Box<dyn Error>> {
let (pool, table_name) = setup_sqlite().unwrap();
return match test_sqlite_json(pool, &table_name) {
Ok(()) => Ok(()),
// @TODO (2019-11-19, Jonathan) Extract sqlite error here
Err(_) => bail!("Error in testing sqlite"),
};
}

fn setup_sqlite() -> SRSResult<(Pool<SqliteConnectionManager>, String)> {
fn setup_pool() -> Pool<SqliteConnectionManager> {
let manager = SqliteConnectionManager::memory();
let pool = Pool::new(manager).unwrap();
pool
}
fn setup_db_structure(pool: &Pool<SqliteConnectionManager>, table_name: &str) -> SRSResult<()> {
let conn = pool.get().unwrap();
conn.execute(
format!(
"CREATE TABLE {} (
id INTEGER PRIMARY KEY,
name TEXT NOT NULL,
time_created TEXT NOT NULL,
data BLOB,
data_null BLOB
)",
table_name
)
.as_str(),
rusqlite::params![],
)?;

conn.execute(
"INSERT INTO person (name, time_created, data, data_null)
VALUES (?1, ?2, ?3, ?4)",
rusqlite::params![
"Steven".to_string(),
&Utc::now(),
"This is some text".to_string(),
None as Option<Vec<u8>>
],
)?;
Ok(())
}

const TABLE_NAME: &str = "person";
let pool = setup_pool();
setup_db_structure(&pool, TABLE_NAME)?;
Ok((pool, TABLE_NAME.to_string()))
}

fn test_sqlite_json(pool: Pool<SqliteConnectionManager>, table_name: &String) -> SRSResult<()> {
let conn = pool.get().unwrap();
let mut stmt = conn.prepare(&format!("SELECT * FROM {}", table_name))?;
let result_iter = stmt.query_map(params![], |row| {
Ok(from_row_s::<Map<String, Value>>(row).unwrap())
})?;
for cur_result in result_iter {
println!(
"Found row macro {:?}",
serde_json::json!(&cur_result.unwrap()).to_string()
);
/*
println!(
"Found row to_string {:?}",
serde_json::to_string(&cur_result.unwrap()).unwrap()
);
*/
}
Ok(())
}

Carregando…
Cancelar
Salvar