How do I keep a global Postgres connection? - postgresql

I want to store the Postgres connection on global scope to access from any function in a module. Here is an example:
use postgres::{Client, NoTls};
static mut client: Option<Client> = None;
pub fn get_player(id: i32) {
// Use global client connection object:
for row in client.unwrap().query("SELECT * FROM public.\"User\" WHERE \"accountID\"=$1;",&[&id]).unwrap(){
let id: i32 = row.get(0);
let name: &str = row.get(1);
println!("found player: {} {}", id, name);
}
}
pub fn init() {
let mut connection = Client::connect("host=localhost user=postgres", NoTls);
match connection {
Ok(cli) => {
println!("Database connected.");
client = Some(cli);
}
Err(_) => println!("Database ERROR while connecting."),
}
}
It is not compiling & working as intended and I don't know how to make this in Rust.

Here is an example with lazy_static and r2d2_postgres that provides a database connection pool:
use r2d2_postgres::postgres::{NoTls, Client};
use r2d2_postgres::PostgresConnectionManager;
#[macro_use]
extern crate lazy_static;
lazy_static! {
static ref POOL: r2d2::Pool<PostgresConnectionManager<NoTls>> = {
let manager = PostgresConnectionManager::new(
// TODO: PLEASE MAKE SURE NOT TO USE HARD CODED CREDENTIALS!!!
"host=localhost user=postgres password=password".parse().unwrap(),
NoTls,
);
r2d2::Pool::new(manager).unwrap()
};
}
pub fn get_player(id: i32) {
// Use global client connection object:
let mut client = POOL.get().unwrap();
for row in client.query("SELECT * FROM public.\"User\" WHERE \"accountID\"=$1;",&[&id]).unwrap(){
let id: i32 = row.get(0);
let name: &str = row.get(1);
println!("found player: {} {}", id, name);
}
}

Related

How to find().lean() in Rust mongodb?

I am trying to make mongodb Document plain in order to apply okapi's open api which does not allow ObjectId in struct.
But I found neither building a find option like
FindOptions::builder().lean().build();
nor
colleciton.find(None, None).lean().await? works.
How do I transform MongoDB Document into JsonSchema?
Example
Before
{
_id: ObjectId,
name: String
}
After
{
_id: String,
name: String
}
You can create custom struct using ObjectId as base and the implement JsonSchema for that custom struct
use mongodb::bson::oid::ObjectId;
use schemars::JsonSchema;
use schemars::schema::Schema;
use schemars::schema::SchemaObject;
use schemars::gen::SchemaGenerator;
use serde::{Serialize, Deserialize};
#[derive(Debug, Serialize, Deserialize)]
pub struct ObjectID(ObjectId);
impl JsonSchema for ObjectID {
fn schema_name() -> String {
stringify!(String).to_owned()
}
fn json_schema(gen: &mut SchemaGenerator) -> Schema {
let mut schema: SchemaObject = <String>::json_schema(gen).into();
schema.number().minimum = Some(1.0);
schema.into()
}
}
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
pub struct Customer {
pub _id: ObjectID,
pub name: String
}
fn main() {
let c = Customer{_id: ObjectID(ObjectId::new()), name: String::from("John")};
println!("{:?}", c);
let serialized = serde_json::to_string(&c).unwrap();
println!("serialized = {}", serialized);
let deserialized: Customer = serde_json::from_str(&serialized).unwrap();
println!("deserialized = {:?}", deserialized);
}
// Output
// Customer { _id: ObjectID(ObjectId("6210af6079e3adc888bef5af")), name: "John" }
// serialized = {"_id":{"$oid":"6210af6079e3adc888bef5af"},"name":"John"}
// deserialized = Customer { _id: ObjectID(ObjectId("6210af6079e3adc888bef5af")), name: "John" }

Encapsulate a postgresql Transaction in a structure

I'm trying to encapsulate a Postgresql transaction and I'm running into some lifetime issue.
Here is the code :
Code
I understand the error message : "returns a value referencing data owned by the current function"
But I have no idea how I could keep my "Transaction" in my the SQLConnection structure.
use postgres::{Client, NoTls, Transaction};
pub struct SQLConnection<'a> {
client: Client,
transaction: Transaction<'a>,
}
impl<'a> SQLConnection<'a> {
pub fn new(connect_string: &str) -> Self {
let mut client = Client::connect(connect_string, NoTls).unwrap();
let transaction = client.transaction().unwrap();
Self {
client,
transaction,
}
}
pub fn commit(&self) {
let _ = self.transaction.commit();
}
pub fn rollback(&self) {
let _ = self.transaction.rollback();
}
}
You' re returning a reference to a value you don't keep. You can't have a reference if there's no owned value.
In your case, there's also no reason to keep both the client and the transaction. Your connection should wrap the client but not the transaction which is a short lived object and shouldn't be kept for more than just the operation.
Your connection should thus just be
pub struct SQLConnection {
client : Client,
}
Then you should, for an operation, get a transaction, use it, then drop it while keeping the connection.
I found a solution that suits my needs. I have now SQLConnection and SQLTransaction and I get the SQLTransation from the my connection.
Now I can use my transaction to group my elementary sql operations.
Here is the code:
use postgres::{Client, NoTls, Transaction};
pub struct SQLConnection {
client: Client,
}
impl SQLConnection {
pub fn new(connect_string: &str) -> Self {
let client = Client::connect(connect_string, NoTls).unwrap();
Self { client }
}
pub fn transaction(&mut self) -> SQLTransaction {
let t = self.client.transaction().unwrap();
SQLTransaction { transaction: t }
}
}
pub struct SQLTransaction<'a> {
transaction: Transaction<'a>,
}
impl<'a> SQLTransaction<'a> {
pub fn new(transaction: Transaction<'a>) -> Self {
Self { transaction }
}
pub fn commit(self) {
let _ = self.transaction.commit();
}
pub fn rollback(self) {
let _ = self.transaction.rollback();
}
}

"cannot find value `a` in this scope" in Rust macro

I created macro for printing, using proc-macro-hack.
Then this error occured though I already have defined a.
Following is the code.
On decl crate,
proc_macro_expr_decl! {
/// Function for printing to the standard output.
///
/// First argument can be literal or not literal.
gprint! => gprint_impl
}
On impl crate,
use syn::{Expr, ExprTuple, parse_str};
use quote::ToTokens;
fn _print_impl(input: &str, print_name: &str) -> String {
let mut input_with_parens = String::with_capacity(input.len() + 2);
input_with_parens.push('(');
input_with_parens.push_str(input);
input_with_parens.push(')');
let tuple = parse_str::<ExprTuple>(&input_with_parens)
.unwrap_or_else(|_| panic!("expected arguments is expressions separated by comma, found {}", input))
let mut arg_iter = tuple.elems.iter();
let first = arg_iter.next();
if first.is_none() {
return "()".to_string();
}
let first = first.unwrap();
let mut s = String::new();
if let &Expr::Lit(ref lit) = first {
s.push_str(print_name);
s.push('(');
s.push_str(&lit.into_tokens().to_string());
} else {
s.push_str(print_name);
s.push_str("(\"{}\", ");
s.push_str(&first.into_tokens().to_string());
}
for arg in arg_iter {
s.push_str(", ");
s.push_str(&arg.into_tokens().to_string());
}
s.push(')');
s
}
proc_macro_expr_impl! {
pub fn gprint_impl(input: &str) -> String {
_print_impl(input, "print!")
}
}
And tried using this macro,
fn main() {
let a = 0;
gprint!(a);
}
error occured:
error[E0425]: cannot find value `a` in this scope
Why?

Rust struct field mutable for socket

I am trying to get started with Rust, and was trying to put some pieces together and have a "Server" instance which contains a Vector of "Clients" where each of them have a Socket.
I understand that in Rust the Socket or TcpStream needs to be mutable, and that I need to borrow the reference in order to keep the scope after the Client instantiation in my main loop.
But I faced the issue that my TcpStream field may not be mutable in the Client struct. So I am not sure my approach is correct, but I tried to solve this using the lifetime parameter <'a>, however this leads me to another problem where my "Client" inside "Server" does not pass the <'a> lifetime parameter.
Can someone help me solve this problem or show me the correct approach to this problem / solution?
Thanks.
use std::net::*;
use std::io::Write;
use std::thread;
use std::time::Duration;
struct Client<'a> {
socket: &'a mut TcpStream,
addr: SocketAddr
}
struct Server {
clients: Vec<Box<Client>>
}
impl Server {
pub fn new() -> Server {
Server{clients: Vec::new()}
}
fn write(&self, stream: &mut TcpStream) {
let mut counter: u32 = 0;
counter += 1;
stream.write(counter.to_string().as_bytes()).unwrap();
thread::sleep(Duration::from_secs(1));
}
fn client_thread(&self, client: &mut Client) {
self.write(&mut client.socket);
}
fn add_client(&self, socket: &mut TcpStream, addr: SocketAddr) {
let mut client = Client {
socket: socket,
addr: addr
};
self.clients.push(Box::new(client));
self.client_thread(&mut client);
}
pub fn server_loop(&self) {
let listener = TcpListener::bind("127.0.0.1:5001").unwrap();
loop {
match listener.accept() {
Ok((mut socket, addr)) => {
println!("new client: {:?}", addr);
thread::spawn(move || loop {
self.add_client(&mut socket, addr);
});
},
Err(e) => println!("couldn't get client: {:?}", e),
}
}
}
}
fn main() {
let mut server = Server::new();
server.server_loop();
}
Update:
The current error message is:
clients: Vec<Box<Client>>
^^^^^^ expected lifetime parameter
Update 2:
Now I think the solution is a little bit better / closer to the goal. But I still have a problem with the thread:spawn outside static context.
use std::net::*;
use std::io::Write;
use std::thread;
struct Client {
socket: TcpStream
}
struct Server {
clients: Vec<Box<Client>>
}
impl Server {
fn new() -> Server {
Server{clients: vec![]}
}
fn write(&mut self, stream: &mut TcpStream) {
let mut counter: u32 = 0;
stream.write(counter.to_string().as_bytes()).unwrap();
}
fn client_loop(&mut self, client: &mut Client) {
loop {
self.write(&mut client.socket);
}
}
fn add_client(&mut self, s: TcpStream) {
let mut client = Client{
socket: s
};
self.clients.push(Box::new(client));
println!("New client: {}", client.socket.peer_addr().unwrap());
thread::spawn(move || {
self.client_loop(&mut client);
});
}
pub fn server_loop(&mut self) {
let listener = TcpListener::bind("127.0.0.1:5001").unwrap();
loop {
match listener.accept() {
Ok((socket, _addr)) => {
self.add_client(socket);
},
Err(e) => println!("Couldn't get client: {}", e),
}
}
}
}
fn main() {
let mut server = Server::new();
server.server_loop();
}
error[E0477]: the type [closure#src/main.rs:38:23: 40:10 self:&mut Server, client:Client] does not fulfill the required lifetime
--> src/main.rs:38:9
|
38 | thread::spawn(move || {
| ^^^^^^^^^^^^^
|
= note: type must satisfy the static lifetime
I was able to solve the overall problem now:
use std::net::*;
use std::io::Write;
use std::thread;
struct Client {
socket: TcpStream,
}
impl Client {
pub fn write(&mut self) {
let counter: u32 = 0;
self.socket.write(counter.to_string().as_bytes()).unwrap();
}
}
struct ClientThread {
inner: Client,
}
impl ClientThread {
pub fn client_loop(&mut self) {
let client = &mut self.inner;
client.write();
}
}
struct Server {
_clients: Vec<Box<Client>>,
}
impl Server {
fn new() -> Server {
Server { _clients: vec![] }
}
fn add_client(&mut self, s: TcpStream) {
let client = Client { socket: s };
println!("New client: {}", client.socket.peer_addr().unwrap());
self._clients.push(Box::new(client));
let mut client_thread = ClientThread { inner: client };
thread::spawn(move || loop {
client_thread.client_loop();
});
}
pub fn server_loop(&mut self) {
let listener = TcpListener::bind("127.0.0.1:5001").unwrap();
loop {
match listener.accept() {
Ok((socket, _addr)) => {
self.add_client(socket);
}
Err(e) => println!("Couldn't get client: {}", e),
}
}
}
}
fn main() {
let mut server = Server::new();
server.server_loop();
}

Alternative way to handle GTK+ events in Rust

Currently, I manage GTK+ events with Rc and RefCell as shown in the following example:
extern crate gtk;
use std::cell::RefCell;
use std::rc::Rc;
use gtk::{Button, ButtonExt, ContainerExt, Inhibit, Label, WidgetExt, Window, WindowType};
use gtk::Orientation::Vertical;
struct Model {
count: i32,
}
fn main() {
gtk::init().unwrap();
let window = Window::new(WindowType::Toplevel);
let model = Rc::new(RefCell::new(Model { count: 0 }));
let vbox = gtk::Box::new(Vertical, 0);
window.add(&vbox);
let label = Label::new(Some("0"));
vbox.add(&label);
let button = Button::new_with_label("Increment");
vbox.add(&button);
window.show_all();
window.connect_delete_event(|_, _| {
gtk::main_quit();
Inhibit(false)
});
{
let model = model.clone();
button.connect_clicked(move |_| {
{
(*model.borrow_mut()).count += 1;
}
label.set_text(&format!("{}", (*model.borrow()).count));
});
}
gtk::main();
}
My main issue with this code is the boilerplate needed because of the RefCells.
Also I feel like it is bad practise and can lead to panics (this is not my main issue so don't propose to use a Mutex because in some examples, that can lead to a deadlock).
So I thought I could handle events in a way similar to Elm: with one function receiving signals where the model could be updated.
However, I am unable to implement this in Rust.
Here is an attempt:
extern crate gtk;
use std::cell::RefCell;
use std::collections::VecDeque;
use std::rc::Rc;
use gtk::{Button, ButtonExt, ContainerExt, Inhibit, Label, WidgetExt, WindowType};
use gtk::Orientation::Vertical;
use Message::Increment;
enum Message {
Increment,
}
struct Window {
label: Label,
model: Model,
queue: Rc<RefCell<VecDeque<Message>>>,
view: gtk::Window,
}
impl Window {
fn new() -> Self {
let window = gtk::Window::new(WindowType::Toplevel);
let vbox = gtk::Box::new(Vertical, 0);
window.add(&vbox);
let label = Label::new(Some("0"));
vbox.add(&label);
let button = Button::new_with_label("Increment");
vbox.add(&button);
window.show_all();
window.connect_delete_event(|_, _| {
gtk::main_quit();
Inhibit(false)
});
let queue = Rc::new(RefCell::new(VecDeque::new()));
{
let queue = queue.clone();
button.connect_clicked(move |_| {
(*queue.borrow_mut()).push_back(Increment);
});
}
Window {
label: label,
queue: queue,
model: Model { count: 0 },
view: window,
}
}
// How to call this method when a message is received?
fn update(&mut self, message: Message) {
match message {
Increment => {
self.model.count += 1;
self.label.set_text(&format!("{}", self.model.count));
},
}
}
}
struct Model {
count: i32,
}
fn main() {
gtk::init().unwrap();
let window = Window::new();
gtk::main();
}
How can I call the update() method when the message queue is updated?
Is it a viable approach?
If not, do you know any alternatives that would provide a solution to this issue?
Perhaps some solution based on the future crate could be used?
In this case, how do I manage both main loops (the gtk+ one and the tokio one).
Or a solution using channels?
I found a solution to this issue here.
Here is what I achieved with my example:
extern crate gtk;
use gtk::{Button, ButtonExt, ContainerExt, Inhibit, Label, WidgetExt, WindowType};
use gtk::Orientation::Vertical;
use Message::Increment;
macro_rules! connect {
($source:ident :: $event:ident, $target:ident :: $message:expr) => {
let target = &mut *$target as *mut _;
$source.$event(move |_| {
let target: &mut Window = unsafe { &mut *target };
target.update($message);
});
};
}
enum Message {
Increment,
}
struct Window {
label: Label,
model: Model,
view: gtk::Window,
}
impl Window {
fn new() -> Box<Self> {
let window = gtk::Window::new(WindowType::Toplevel);
let vbox = gtk::Box::new(Vertical, 0);
window.add(&vbox);
let label = Label::new(Some("0"));
vbox.add(&label);
let button = Button::new_with_label("Increment");
vbox.add(&button);
window.show_all();
window.connect_delete_event(|_, _| {
gtk::main_quit();
Inhibit(false)
});
let mut window = Box::new(Window {
label: label,
model: Model { count: 0 },
view: window,
});
connect!(button::connect_clicked, window::Increment);
window
}
fn update(&mut self, message: Message) {
match message {
Increment => {
self.model.count += 1;
self.label.set_text(&format!("{}", self.model.count));
},
}
}
}
struct Model {
count: i32,
}
fn main() {
gtk::init().unwrap();
let _window = Window::new();
gtk::main();
}
Do you think this use of unsafe can cause segfault?
For instance, if the button could outlive the window, the window could be used after being freed, no?
Is there a way to build a safe wrapper around this?
On an esthetical note, is there a way to achieve this:
connect!(button::clicked, window::Increment);