Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Rust e database relazionali

Rust: impariamo le basi per lo sviluppo di applicazioni in grado di interagire con i database relazionali tramite linguaggio SQL
Rust: impariamo le basi per lo sviluppo di applicazioni in grado di interagire con i database relazionali tramite linguaggio SQL
Link copiato negli appunti

Quasi ogni progetto, anche uno basato su Rust, ha necessità di memorizzare dei dati. In molti casi, si ricorre al salvataggio su file, in tanti altri in cui è importante fondarsi su una struttura di memorizzazione ben articolata si integra nei progetti un database.

In questa lezione, vedremo come fare in modo che il linguaggio Rust riesca a dialogare con un database relazionale e nello specifico un database di tipo MySQL. Nel caso di questo esempio lo avvieremo tramite Docker ma qualora si preferissero altre modalità o si avesse a disposizione una propria installazione già pronta ci si ritenga liberi di procedere altrimenti: la sostanza della lezione non cambierà minimamente.

Rust e SQL

Inutile dire che un linguaggio come Rust dispone di tante alternative per l'interazione con un database relazionale. Qui abbiamo usato una soluzione piuttosto tipica - il crate mysql - che permette di personalizzare il lavoro a proprio piacimento seguendo un flusso piuttosto tipico - non complesso da imparare se si hanno già avute esperienze simili in altri linguaggi - sfruttando anche la disponibilità di un connection pool. Esistono tuttavia tante altre alternative che non vedremo qui tra cui Diesel, un Object Relational Model (ORM) per PostgreSQL, Sqlite nonchè MySQL e sqlx che permette anch'esso l'interazione con diversi sistemi per database relazionali.

Prepariamo l'esempio: il database

Nel nostro esempio, procederemo con operazioni "scolastiche" ma molto utili di inserimento e lettura di dati da una tabella MySQL pertanto, per prima cosa, avremo bisogno del database.

Come anticipato, lo avvieremo con Docker in questo modo:

docker run -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=topolino mysql

e connettendoci tramite il client mysql creiamo una tabella in cui aggregheremo dati a proposito di operazioni bancarie (una sorta di estratto conto):

$ mysql -h 172.17.0.2 -u root -p
...
mysql> CREATE DATABASE banca;
Query OK, 1 row affected (0.01 sec)
mysql> USE banca;
Database changed
mysql> SHOW TABLES;
Empty set (0.00 sec)
mysql> CREATE TABLE operazioni (
    ->     id int not null,
    ->     importo FLOAT not null,
    ->     operazione TEXT);
Query OK, 0 rows affected (0.03 sec)
mysql> SHOW TABLES;
+-----------------+
| Tables_in_banca |
+-----------------+
| operazioni      |
+-----------------+

Collegandoci al sistema (nel nostro caso, indirizzo IP 172.17.0.2) abbiamo creato un database di nome banca e la tabella operazioni: si noti in proposito il cambio di prompt tra il sistema operativo ($) e l'ingresso in MySQL (mysql>).

Ora che è tutto pronto passiamo al vero e proprio programma Rust.

Il codice

Usiamo cargo per la gestione del progetto e, nel file di configurazione Cargo.toml, inseriamo l'annotazione per le dipendenze:

[dependencies]
mysql = "*"

Il programma che segue - puntualmente illustrato da commenti - crea un vettore di dati strutturati sulla struct OperazioneBancaria composta da tre semplici campi (identificativo operazione, importo e descrizione dell'operazione). I dati di ognuno di questi elementi vengono iniettati nella tabella per poi, alla fine, essere letti con una query:

// importiamo le librerie di cui abbiamo bisogno
use mysql::*;
use mysql::prelude::Queryable;
// creazione di una Struct di base per organizzare le nostre unità informative
struct OperazioneBancaria {
    id: i32,
    importo: f32,
    operazione: Option<String>,
}
fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
    // impostiamo la stringa di connessione
    let conn_string = "mysql://root:topolino@172.17.0.2:3306/banca";
    // apriamo un pool di connesstioni e ne estraiamo una
    let conn_pool = Pool::new(conn_string)?;
    let mut conn = conn_pool.get_conn()?;
    // prepariamo una batteria di struct da salvare nel database
    let operazioni = vec![
        OperazioneBancaria { id: 1, importo: 230.00, operazione: Some("Accredito dal conto nr. 6789876".to_owned()) },
        OperazioneBancaria { id: 2, importo: -150.00, operazione: Some("Pagobancomat presso Pizzeria Carmelo".to_owned()) },
        OperazioneBancaria { id: 3, importo: -70.00, operazione: Some("Pagobancomat presso Abiti da sogno".to_owned()) },
        OperazioneBancaria { id: 4, importo: 211.00, operazione: Some("Versamento in contanti".to_owned()) }
    ];
    // programmiamo l'inserimento all'interno della tabella operazioni
    conn.exec_batch(
        r"INSERT INTO operazioni (id, importo, operazione)
          VALUES (:id, :importo, :operazione)",
        operazioni.iter().map(|p| params! {
            "id" => p.id,
            "importo" => p.importo,
            "operazione" => &p.operazione,
        })
    )?;
    // eseguiamo la lettura dei dati tramite query
    let risultato = conn.query_map(
            "SELECT id, importo, operazione from operazioni",
            |(id, importo, operazione)| {
                OperazioneBancaria { id, importo, operazione }
            },
        )?;
    // iteriamo tra i risultati per stamparne il contenuto
    for  operazione in risultato.iter(){
        println!("Id: {} importo: {} euro   {}",
            &operazione.id,
            &operazione.importo,
            &operazione.operazione.as_ref().unwrap()
            );
    }
    Ok(())
}

L'output dell'applicazione Rust

L'output finale che dimostra sia l'effettivo inserimento sia il concreto recupero è il seguente (avviato con il comando cargo run):

Id: 1 importo: 230 euro   Accredito dal conto nr. 6789876
Id: 2 importo: -150 euro   Pagobancomat presso Pizzeria Carmelo
Id: 3 importo: -70 euro   Pagobancomat presso Abiti da sogno
Id: 4 importo: 211 euro   Versamento in contanti

e anche accedendo al database MySQL direttamente si può notare l'effettiva esistenza dei dati memorizzati in maniera persistente:

mysql> SELECT * FROM operazioni;
+----+---------+--------------------------------------+
| id | importo | operazione                           |
+----+---------+--------------------------------------+
|  1 |     230 | Accredito dal conto nr. 6789876      |
|  2 |    -150 | Pagobancomat presso Pizzeria Carmelo |
|  3 |     -70 | Pagobancomat presso Abiti da sogno   |
|  4 |     211 | Versamento in contanti               |
+----+---------+--------------------------------------+

A questo punto, nonostante l'essenzialità dell'esempio, la strada per l'integrazione di un database relazionale è spianata. Con la conoscenza del linguaggio SQL potremo definire operazioni che tramite codice simile a questo potranno essere inoltrate direttamente al database.

Ti consigliamo anche