IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Rust Discussion :

[Linux][Rust 1.69.0][mysql] Débutant en Rust de chez Debutant(R)


Sujet :

Rust

  1. #1
    Membre averti

    Homme Profil pro
    Enseignant
    Inscrit en
    septembre 2012
    Messages
    301
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : septembre 2012
    Messages : 301
    Points : 353
    Points
    353
    Par défaut [Linux][Rust 1.69.0][mysql] Débutant en Rust de chez Debutant(R)
    Salutations !!

    Je suis en train d'apprendre le Rust, et comme je fais en général quand j'apprends un nouveau langage je reprends des programmes écrits initialement dans d'autres langages comme le C, Perl, Assembler, C++, Java, ... et j'essaye de les porter.
    Ici, je voudrais "simplement" reprendre un programme en C à l'origine qui interroge une base de données et qui affiche les résultats de la requête.

    Je suis tombé malade en lisant les indications autant dans la documentation en ligne que dans les bouquins concernant la prise en charge de la gestion des bases de données en Rust :{

    Voilà ce que j'ai pour l'instant, ne faites pas attention au caractère "grossier" des messages, je fais cela pour moi et ça me fait rire... enfantillages et consors.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    use mysql::*;
    use text_colorizer::*;
    
    const DB_HOST :&str = "192.168.0.4";
    const DB_USER :&str = "magicuser";
    const DB_PASSWD :&str = "resucigam";
    const DB_NAME :&str = "MagicArena";
    
    #[derive(Clone)]
    struct TablePlayers
    {
        idplayer :u16,
        alias: String,
        couleurs: u8,
        victories: u16,
        conceded: u16,
        defeated: u16,
        draws: u16,
        myscore: u64,
        hiscore: u64,
        matchesdone: u16
    }
    
    fn main()
    {
        println!("magicstats v0.0.1 RUST");
        print!("Tentative de connexion à la base de données MagicArena...");
    
        let errorcode = doconnect();
        match errorcode
        {
            Ok(myconnexion) =>
                {
                    print!("...{}\n", "OK".green().bold());
                    // pas envie de commencer à traiter les données ici j'aimerais le faire en dehors de ce bloc... mais je n'y arrive pas
                },
            Err(ref erreurdemerde) =>
                {
                    println!("{}", "ERREUR !! B**** DE M**** :{".blink().red());
                    println!("{} {}", "Pas moyen de se connecter parce que =>".yellow().bold(), erreurdemerde.to_string().yellow());
                    std::process::exit(2);
                }
        }
        // myconnexion est inconnue ici évidemment
    }
    
    fn doconnect() -> std::result::Result<PooledConn, Error> // je suis obligé à cause d'un traits provenant de PooledConn si mes souvenirs sont bons...
    {
        let url = "mysql://".to_owned()+DB_USER+":"+DB_PASSWD+"@"+DB_HOST+"/"+DB_NAME;
        let pool = Pool::new(&*url);
        let conn = pool?.get_conn();
    
        conn
    }
    Avec ceci je peux déterminer si la connexion s'effectue à la base de données c'est super MAIS... pour la suite c'est l'horreur... je trouve que le Perl est largement plus lisible que le Rust quand on voit ce genre de choses:

    let selected_payments = conn
    .query_map(
    "SELECT customer_id, amount, account_name from payment",
    |(customer_id, amount, account_name)| {
    Payment { customer_id, amount, account_name }
    },
    )?;
    ...ou bien pire...

    let all_persons: Vec<Person> =
    pool.prep_exec("SELECT person_id, person_name from person", ())

    .map(|result| {
    result.map(|x| x.unwrap()).map(|row| {
    let (person_id, person_name) = mysql::from_row(row);

    Person {
    person_id,
    person_name
    }
    }).collect()
    }).unwrap(); // Unwrap `Vec<Person>`

    for person in all_persons.iter() {
    println!("{}: {}", person.person_id, person.person_name);
    }
    ...
    ...je n'ai pas encore tout exploré en matière d'interface base de données pour Rust, j'espère qu'il y a quelque chose de similaire à perl-dbi en Rust parce que si je dois à chaque fois me farcir ce genre d'horreur pour effectuer
    de simples requêtes (le PDO PHP qui me fait vômir m'a finalement l'air pas si indigeste au vu de ce que je vois), ...

    Questions:
    Comment faire pour que la fonction doconnect retourne un objet de type PooledConn au lieu d'un Result<...> ?
    Ca me gave de toujours devoir faire des match ceci et Ok(cela) Err(brol) à tout bout de champs avec, en plus, la création de "variables locales" à la portée limitée au bloc où elles sont créées :{

    Créer une variable globale (mot clef static) c'est la croix et la banière, je ne trouve pas l'équivalent au mot clef "null" qui me tirerait, à mon avis d'affaire.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    static thisconnexion :PooledConn = std::ptr::null; // ça ne marche pas -> erreur à la compilation
    Existe-t-il quelque chose d'aussi simple en Rust que ceci en matière d'accès simple à une DB ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    my $statement=$DBHandler->prepare("SELECT AES_DECRYPT(UNHEX(gmailuser),734),AES_DECRYPT(UNHEX(gmailpass),734) FROM Security");
    $statement->execute();
     
    ($imaplogin,$imappass)=$statement->fetchrow_array();

  2. #2
    Expert éminent sénior Avatar de Uther
    Homme Profil pro
    Tourneur Fraiseur
    Inscrit en
    avril 2002
    Messages
    4 519
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Tourneur Fraiseur

    Informations forums :
    Inscription : avril 2002
    Messages : 4 519
    Points : 14 974
    Points
    14 974
    Par défaut
    Visiblement, tu utilises directement une bibliothèque mysql de bas niveau, donc en effet l'interface est complexe et tu vas avoir à gérer pas mal de choses manuellement.

    Tu as heureusement des outils qui aident à abstraire une partie de la base de données, comme par exemple sqlx qui va t'assister à faire des requêtes contrôlées. Si tu veux aussi du mapping d'objet basique, tu as ormx, et pour des ORM plus avancés, tu as Diesel ou SeaORM .

  3. #3
    Membre averti

    Homme Profil pro
    Enseignant
    Inscrit en
    septembre 2012
    Messages
    301
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : septembre 2012
    Messages : 301
    Points : 353
    Points
    353
    Par défaut
    C'est en écrivant le post -- j'étais un peu vénère -- que j'ai vu des articles qui parlent de Diesel... je vais tenter de me documenter.
    Merci pour les pistes, je sens que je vais passer des nuits à lire moi lol ^^

  4. #4
    Expert éminent sénior Avatar de Uther
    Homme Profil pro
    Tourneur Fraiseur
    Inscrit en
    avril 2002
    Messages
    4 519
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Tourneur Fraiseur

    Informations forums :
    Inscription : avril 2002
    Messages : 4 519
    Points : 14 974
    Points
    14 974
    Par défaut
    Si tu veux quelque chose de simple pour commencer, je te conseille de partir sur sqlx. Diesel est utile mais plus complexe a mettre en place.

  5. #5
    Membre expérimenté
    Avatar de sambia39
    Homme Profil pro
    No Comment
    Inscrit en
    mai 2010
    Messages
    542
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : No Comment
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : mai 2010
    Messages : 542
    Points : 1 730
    Points
    1 730
    Par défaut
    Bonjour,
    Citation Envoyé par hurukan Voir le message
    Salutations !!
    Questions:
    Comment faire pour que la fonction doconnect retourne un objet de type PooledConn au lieu d'un Result<...> ?
    Ca me gave de toujours devoir faire des match ceci et Ok(cela) Err(brol) à tout bout de champs avec, en plus, la création de "variables locales" à la portée limitée au bloc où elles sont créées :{

    Créer une variable globale (mot clef static) c'est la croix et la banière, je ne trouve pas l'équivalent au mot clef "null" qui me tirerait, à mon avis d'affaire.
    Il n'est pas possible de modifier la signature de retour d'une fonction, car la signature de retour dépend du type de données retournées par la fonction. Et il me semble à défaut de m’être trompé que vous n'avez pas saisi l'intérêt de Result (mais vous pouvez également faire sans Result voir exemple ci-dessous enfin plus bas !)

    En Rust, Results vous permet d'encapsuler le résultat d'une opération qui pourrait échouer. Il accepte en paramètre un type de donnée qui sera renvoyé en cas de succès et un type d'erreur en cas d'échec, ce qui évite la gestion d'erreur lourde comme les try-catch à titre d’exemple. Dans la situation actuelle, votre fonction a bien une signature correcte avec un Result et donc si elle réussit, elle renvoie bien un objet PooledConn, sinon elle renvoie le type d'erreur spécifié. Ainsi donc en cas de succès, aucune gestion d’erreur supplémentaire n'est nécessaire dans la fonction. Pour s’en rendre compte voici deux exemples dont l’un renvoie un PooledConn et l’autre est encapsulé avec Result<PooledConn, Error>
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    /* 
    * Attention les instructions suivantes sont des instructions  factuelles à ne pas utiliser 
    * dans un programme elles décrivent juste  une manière de  gérer les erreurs de la fonction 
    * en fonction de sa  signature.
    */
    
    fn connect() -> Result<PooledConn, Error> { 
       let addrdb = "addressBidon".to_owned()+DB_USER+":"+DB_PASSWD+"@"+DB_HOST+"/"+DB_NAME; 
      let pool = Pool::new(&*addrdb); 
     match pool {         
       Ok(p) => Ok(p.get_conn()),         
       Err(e) => Err(e),     
     } 
    }
    
    //et
    
    fn connect() -> PooledConn { 
         let addrdb = "addressBidon".to_owned()+DB_USER+":"+DB_PASSWD+"@"+DB_HOST+"/"+DB_NAME; 
    let pool = Pool::new(&*addrdb);     
    match pool { 
     Ok(p) => p.get_conn(),         
     Err(e) => panic!("Erreur lors de la connexion : {}", e),     
      }
    }
    
    Vous remarquerez que l'une des deux fonctions "doconnect() "peut échouer et renvoyer une erreur si elle ne peut pas se connecter à la base de données facilitant au passage la gestion de l'erreur en la faisant remonter; contrairement à l'autre fonction qui invoque volontairement la macro Panic ! pour générer une erreur fatale et signifier que le programme ne peut pas continuer à s'exécuter. Certes une fois que Panic! est appelé, le programme s'arrête immédiatement et un message d'erreur est affiché mais il est réservé pour des besoins justifiés. De l'exemple il faut comprendre que la gestion des erreurs est faites dans la fonction mais pas traité de la même façon .

    Citation Envoyé par hurukan Voir le message
    Existe-t-il quelque chose d'aussi simple en Rust que ceci en matière d'accès simple à une DB ?
    Malheureusement, ‬à ma connaissance ‬il n'y a pas ou du moins pas un équivalent du mot-clé Null en Rust. ‬En Rust, ‬les variables et où les objets ne peuvent pas être initialisés à une valeur nulle. Les variables en Rust doivent être initialisées à une valeur par défaut, qui sont généralement définis par vous cela peut être une valeur décimale ; ‬true ou false ou autres ( let mut bidule = HashMap::new(); ) . Cependant vous pouvez utiliser «Option» qui permet de gérer les valeurs nulle. Cela vous permet d’être en accord de convention rust (si je peux ainsi le dire) pour gérer les variables et les objets qui peuvent être initialisés à une valeur nulle exemple: let mut machin: Option<i32> = None; cela définit une variable mutable "machin" qui peut être initialisée à une valeur nulle. Vous pouvez ensuite utiliser match pour tester si un objet est nul ou pas.

    Aussi; si vous utilisez std::process::exit() il est préférable de faire remonter l'information à la fonction appelante qui va prendre les mesures nécessaires adaptées; car il faut comprendre que certes std::processus::exit() ne renvoie rien et met fin au programme en transmettant le code de sortie au système d'exploitation, mais il n'appelle aucun destructeur, ce qui signifie que vous devrez tout détruire vous-même avant de exit c'est pour cela qu'il est recommandé d'appeler la fonction lorsque vous êtes sûr qu'il n'y a pas de destructeurs disponibles.

    à bientôt
    Celui qui peut, agit. Celui qui ne peut pas, enseigne.
    Il y a deux sortes de savants: les spécialistes, qui connaissent tout sur rien,
    et les philosophes, qui ne connaissent rien sur tout.
    George Bernard Shaw

  6. #6
    Membre averti

    Homme Profil pro
    Enseignant
    Inscrit en
    septembre 2012
    Messages
    301
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : septembre 2012
    Messages : 301
    Points : 353
    Points
    353
    Par défaut
    Bin oui à tous nouveaux langages nouvelles approches il faudra bien que je m'y habitue ^^
    Rust est vraiment séduisant, bon, il y a des "bizarreries" syntaxiques mais ayant programmé en Perl et Java je finirais bien par m'y habituer.

    J'ai testé Diesel... je m'en sors pas.
    Je vais tester sqlx, pour voir...

    17 | let result = Players.limit(5).load::<Players>(&mut connection).expect("Zut !! Flûte !!");
    | ---- ^^^^^^^^^^^^^^^ the trait `FromSqlRow<_, _>` is not implemented for `table`
    | |
    | required by a bound introduced by this call

    17 | let result = Players.limit(5).load::<Players>(&mut connection).expect("Putain !!");
    | ---- ^^^^^^^^^^^^^^^ the trait `load_dsl::private::CompatibleType<table, _>` is not implemented for `(SmallInt, Text, diesel::sql_types::Binary, SmallInt, SmallInt, SmallInt, TinyInt, BigInt, BigInt, SmallInt)`
    | |
    | required by a bound introduced by this call
    Voici les fichiers model.rs et schema.rs

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #[derive(Queryable)]
    pub struct TablePlayers
    {
         pub idplayer : u16,
         pub alias: Option<String>,
         pub couleurs: ,
         pub victories: u32,
         pub conceded: u32,
         pub defeated: u32,
         pub draws: u8,
         pub myscore: i64,
         pub hiscore: i64,
         pub matchesdone: u32
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    diesel::table!
    {
    	Players (idPlayer)
    	{
    		idPlayer -> SmallInt,
    		Alias -> Varchar,
    		Couleurs -> Binary,
    		Victories -> SmallInt,
    		Conceded -> SmallInt,
    		Defeated -> SmallInt,
    		Draws -> TinyInt,
    		MyScore -> BigInt,
    		HisScore -> BigInt,
    		MatchesDone -> SmallInt,
    	}
    }
    ...il y a encore quelque chose que j'ai pas tout à fait compris concernant les traits... j'essaie d'ajouter un #[derive ...] mais déjà je sais pas trop quoi ajouter ^^

  7. #7
    Membre averti

    Homme Profil pro
    Enseignant
    Inscrit en
    septembre 2012
    Messages
    301
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Enseignant
    Secteur : Enseignement

    Informations forums :
    Inscription : septembre 2012
    Messages : 301
    Points : 353
    Points
    353
    Par défaut
    fonctionne toujours pas... je sais pas pourquoi je comprends pas...


    let results = Players.load::<Players>(&mut connection).expect("Error loading datas -- p****n de b****l de m***e");
    | ---- ^^^^^^^^^^^^^^^ the trait `FromSqlRow<_, _>` is not implemented for `table`

    FromSqlRow vient de diesel::deserialize mais je dois faire quoi moi ?
    Modifier le schema.rs, le model.rs ?

    schema.rs
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    diesel::table!
    {
    	scPlayers (idPlayers)
    	{
    		idPlayers -> SmallInt,
    		Alias -> VarChar,
    		Couleurs -> VarChar,
    		Victories -> SmallInt,
    		Conceded -> SmallInt,
    		Defeated -> SmallInt,
    		Draws -> SmallInt,
    		MyScore -> BigInt,
    		HisScore -> BigInt,
    		MatchesDone -> SmallInt
    	}
    }
    model.rs

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     
    use diesel::prelude::Queryable;
    use serde::Serialize;
     
    #[derive(Queryable,Serialize)]
    pub struct Players
    {
    	pub idPlayer: u32,
    	pub Alias: Option<String>,
    	pub Couleurs: u8,
    	pub Victories: u32,
    	pub Conceded: u32,
    	pub Defeated: u32,
    	pub Draws: u32,
    	pub MyScore: u64,
    	pub HisScore: u64,
    	pub MatchesDone: u32
    }

Discussions similaires

  1. [MYSQL] [débutant] utiliser replace avec mysql.pas
    Par alex01pernot dans le forum Bases de données
    Réponses: 2
    Dernier message: 30/08/2006, 21h23
  2. [Flash MX 2004] Php Mysql (débutant)
    Par mooky dans le forum Flash
    Réponses: 7
    Dernier message: 08/02/2006, 20h55
  3. accès distants à mysql (débutant)
    Par seb0026 dans le forum Débuter
    Réponses: 1
    Dernier message: 10/10/2005, 22h41

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo