Repository: launchbadge/sqlx
File: examples/postgres/chat/src/main.rs (Rust)

Code before:

struct ChatApp {
    input: String,
    messages: Arc<Mutex<Vec<String>>>,
    pool: PgPool,
}

impl ChatApp {
    fn new(pool: PgPool) -> Self {
        ChatApp {
            input: String::new(),
            messages: Arc::new(Mutex::new(Vec::new())),
            pool,
        }
    }

    async fn run<B: Backend>(
        mut self,
        terminal: &mut Terminal<B>,
        mut listener: PgListener,
    ) -> Result<(), Box<dyn Error>> {
        // setup listener task
        let messages = self.messages.clone();
        std::mem::drop(tokio::spawn(async move {
            while let Ok(msg) = listener.recv().await {
                messages.lock().await.push(msg.payload().to_string());
            }
        }));

        loop {
            let messages: Vec<ListItem> = self
                .messages
                .lock()
                .await
                .iter()
                .map(|m| {
                    let content = vec![Spans::from(Span::raw(m.to_owned()))];
                    ListItem::new(content)
                })
                .collect();

            terminal.draw(|f| self.ui(f, messages))?;

            if !event::poll(Duration::from_millis(20))? {
                continue;
            }

            if let Event::Key(key) = event::read()? {
                match key.code {
                    KeyCode::Enter => {
                        notify(&self.pool, self.input.drain(..).collect()).await?;

Review comment (suggestion):
I would prefer to see this use a channel, but for this simple example it doesn't really matter.

However, `msg.payload().to_string()` is making me think we should add a `.into_payload()` to `PgNotification`.

Code after:

struct ChatApp {
    input: String,
    messages: Arc<Mutex<Vec<String>>>,
    pool: PgPool,
}

impl ChatApp {
    fn new(pool: PgPool) -> Self {
        ChatApp {
            input: String::new(),
            messages: Arc::new(Mutex::new(Vec::new())),
            pool,
        }
    }

    async fn run<B: Backend>(
        mut self,
        terminal: &mut Terminal<B>,
        mut listener: PgListener,
    ) -> Result<(), Box<dyn Error>> {
        // setup listener task
        let messages = self.messages.clone();
        tokio::spawn(async move {
            while let Ok(msg) = listener.recv().await {
                messages.lock().await.push(msg.payload().to_string());
            }
        });

        loop {
            let messages: Vec<ListItem> = self
                .messages
                .lock()
                .await
                .iter()
                .map(|m| {
                    let content = vec![Spans::from(Span::raw(m.to_owned()))];
                    ListItem::new(content)
                })
                .collect();

            terminal.draw(|f| self.ui(f, messages))?;

            if !event::poll(Duration::from_millis(20))? {
                continue;
            }

            if let Event::Key(key) = event::read()? {
                match key.code {
                    KeyCode::Enter => {
                        notify(&self.pool, &self.input).await?;