|
| 1 | +#[cfg(test)] |
| 2 | +mod tests { |
| 3 | + use crate::common::{clear, insert, query, random_id, random_limited, trace}; |
| 4 | + use chrono::NaiveDate; |
| 5 | + use rand::{seq::IndexedRandom, Rng}; |
| 6 | + use serde_json::Value; |
| 7 | + use tokio_postgres::types::ToSql; |
| 8 | + use tracing::info; |
| 9 | + |
| 10 | + fn value_for_type(t: &str) -> Box<dyn ToSql + Sync> { |
| 11 | + let mut rng = rand::rng(); |
| 12 | + |
| 13 | + match t { |
| 14 | + "i16" => Box::new(rng.random_range(1..=i16::MAX) as i16), |
| 15 | + "i32" => Box::new(rng.random_range(1..=i32::MAX) as i32), |
| 16 | + "i64" => Box::new(rng.random_range(1..=i64::MAX) as i64), |
| 17 | + "f64" => Box::new(rng.random_range(1.0..=f64::MAX) as f64), |
| 18 | + "bool" => Box::new(rand::random_bool(0.5) as bool), |
| 19 | + "String" => { |
| 20 | + let i = random_limited(); |
| 21 | + Box::new(((b'A' + (i - 1) as u8) as char).to_string()) |
| 22 | + } |
| 23 | + "NaiveDate" => { |
| 24 | + let i = random_limited(); |
| 25 | + Box::new(NaiveDate::parse_from_str(&format!("2023-01-{}", i), "%Y-%m-%d").unwrap()) |
| 26 | + } |
| 27 | + "Value" => { |
| 28 | + let i = rng.random_range(1..=i32::MAX) as i32; |
| 29 | + Box::new(serde_json::json!({"n": i, "s": format!("{}", i) })) |
| 30 | + } |
| 31 | + |
| 32 | + _ => panic!("Unknown type {t}"), |
| 33 | + } |
| 34 | + } |
| 35 | + |
| 36 | + /// |
| 37 | + /// Generates a random number of columns and values |
| 38 | + /// Return as a tuple of two vecs: |
| 39 | + /// - first vec contains column names |
| 40 | + /// - second vec contains values of the corresponding column type |
| 41 | + pub fn generate_columns_with_values() -> (Vec<String>, Vec<Box<(dyn ToSql + Sync)>>) { |
| 42 | + let columns = vec![ |
| 43 | + ("i16", "int2"), |
| 44 | + ("i32", "int4"), |
| 45 | + ("i64", "int8"), |
| 46 | + ("f64", "float8"), |
| 47 | + ("bool", "bool"), |
| 48 | + ("String", "text"), |
| 49 | + ("NaiveDate", "date"), |
| 50 | + ("Value", "jsonb"), |
| 51 | + ]; |
| 52 | + |
| 53 | + let mut rng = rand::rng(); |
| 54 | + let n = rng.random_range(1..columns.len()); |
| 55 | + |
| 56 | + let (mut columns, mut values): (Vec<_>, Vec<_>) = columns |
| 57 | + .choose_multiple(&mut rng, n) |
| 58 | + .map(|(t, c)| { |
| 59 | + let c = format!("encrypted_{c}"); |
| 60 | + (c, value_for_type(t)) |
| 61 | + }) |
| 62 | + .unzip(); |
| 63 | + |
| 64 | + let id = Box::new(random_id()); |
| 65 | + columns.insert(0, "id".to_string()); |
| 66 | + values.insert(0, id); |
| 67 | + |
| 68 | + (columns, values) |
| 69 | + } |
| 70 | + |
| 71 | + pub async fn query<T: for<'a> tokio_postgres::types::FromSql<'a> + Send + Sync>( |
| 72 | + sql: &str, |
| 73 | + ) -> Vec<T> { |
| 74 | + let client = connect_with_tls(PROXY).await; |
| 75 | + let rows = client.query(sql, &[]).await.unwrap(); |
| 76 | + rows.iter().map(|row| row.get(0)).collect::<Vec<T>>() |
| 77 | + } |
| 78 | + |
| 79 | + #[tokio::test] |
| 80 | + pub async fn test_everything_all_at_once() { |
| 81 | + trace(); |
| 82 | + |
| 83 | + clear().await; |
| 84 | + |
| 85 | + let (columns, values) = generate_columns_with_values(); |
| 86 | + |
| 87 | + info!("Columns: {:?}", columns.join(",")); |
| 88 | + info!("Values: {:?}", values); |
| 89 | + |
| 90 | + let columns = columns.join(", "); |
| 91 | + let params: Vec<&(dyn ToSql + Sync)> = values.iter().map(|v| v.as_ref()).collect(); |
| 92 | + |
| 93 | + let placeholders = (1..=values.len()) |
| 94 | + .map(|i| format!("${}", i)) |
| 95 | + .collect::<Vec<_>>() |
| 96 | + .join(", "); |
| 97 | + |
| 98 | + let sql = format!("INSERT INTO encrypted ({columns}) VALUES ({placeholders})"); |
| 99 | + |
| 100 | + info!(sql); |
| 101 | + insert(&sql, ¶ms).await; |
| 102 | + |
| 103 | + let sql = format!("SELECT {columns} FROM encrypted WHERE id = $1"); |
| 104 | + |
| 105 | + // let actual = query_by::<$type>(&sql, &id).await; |
| 106 | + |
| 107 | + // assert_eq!(expected, actual); |
| 108 | + } |
| 109 | + |
| 110 | + // test_insert_with_params!(insert_with_params_int2, i16, int2); |
| 111 | + // test_insert_with_params!(insert_with_params_int4, i32, int4); |
| 112 | + // test_insert_with_params!(insert_with_params_int8, i64, int8); |
| 113 | + // test_insert_with_params!(insert_with_params_float8, f64, float8); |
| 114 | + // test_insert_with_params!(insert_with_params_bool, bool, bool); |
| 115 | + // test_insert_with_params!(insert_with_params_text_only, String, text); |
| 116 | + // test_insert_with_params!(insert_with_params_date, NaiveDate, date); |
| 117 | + // test_insert_with_params!(insert_with_params_jsonb, Value, jsonb); |
| 118 | +} |
0 commit comments