Question

J'ai du code qui doit s’assurer que certaines données se trouvent dans un enum mysql avant leur insertion dans la base de données. Le moyen le plus propre que j'ai trouvé est le code suivant:

sub enum_values {
    my ( $self, $schema, $table, $column ) = @_;

    # don't eval to let the error bubble up
    my $columns = $schema->storage->dbh->selectrow_hashref(
        "SHOW COLUMNS FROM `$table` like ?",
        {},
        $column
    );

    unless ($columns) {
        X::Internal::Database::UnknownColumn->throw(
            column => $column,
            table  => $table,
        );
    }

    my $type = $columns->{Type} or X::Panic->throw(
        details => "Could not determine type for $table.$column",
    );

    unless ( $type =~ /\Aenum\((.*)\)\z/ ) {
        X::Internal::Database::IncorrectTypeForColumn->throw(
            type_wanted => 'enum',
            type_found  => $type,
        );
    }
    $type = $1;

    require Text::CSV_XS;
    my $csv = Text::CSV_XS->new;
    $csv->parse($type) or X::Panic->throw(
        details => "Could not parse enum CSV data: ".$csv->error_input,
    );
    return map { /\A'(.*)'\z/; $1 }$csv->fields;
}

Nous utilisons DBIx :: Class . Il y a sûrement un meilleur moyen d'accomplir cela? (Notez que la variable $ table provient de notre code, pas de toute source externe. Donc, pas de problème de sécurité).

Était-ce utile?

La solution

Pas besoin d'être aussi héroïque. Utilisation d'une version relativement moderne de DBD :: mysql , le hachage renvoyé par colonne info cette méthode contient une version pré-scindée des valeurs enum valides dans la clé mysql_values ??:

.
my $sth = $dbh->column_info(undef, undef, 'mytable', '%');

foreach my $col_info ($sth->fetchrow_hashref)
{
  if($col_info->{'TYPE_NAME'} eq 'ENUM')
  {
    # The mysql_values key contains a reference to an array of valid enum values
    print "Valid enum values for $col_info->{'COLUMN_NAME'}: ", 
          join(', ', @{$col_info->{'mysql_values'}}), "\n";
  }
  ...
}

Autres conseils

Je dirais que l'utilisation de Text :: CSV_XS peut être une overkill, sauf si vous avez des choses étranges comme des virgules dans les énumérations (une mauvaise idée quand même, si vous me le demandez). J'utiliserais probablement ceci à la place.

my @fields = $type =~ / ' ([^']+) ' (?:,|\z) /msgx;

À part cela, je ne pense pas qu'il existe de raccourcis.

J'ai passé une partie de la journée à poser la même question au canal # dbix de MagNet et je suis tombé sur ce manque de réponse. Puisque j'ai trouvé la réponse et que personne d'autre ne semble l'avoir fait pour l'instant, je vais coller la transcription en dessous du TL; DR ici:

my $cfg = new Config::Simple( $rc_file );
my $mysql = $cfg->get_block('mysql');
my $dsn =
  "DBI:mysql:database=$mysql->{database};".
  "host=$mysql->{hostname};port=$mysql->{port}";

my $schema  =
  DTSS::CDN::Schema->connect( $dsn, $mysql->{user}, $mysql->{password} );

my $valid_enum_values =
  $schema->source('Cdnurl')->column_info('scheme')->{extra}->{list};

Et maintenant, le journal de bord IRC me frappant la tête contre un mur:

14:40 < cj> is there a cross-platform way to get the valid values of an 
            enum?
15:11 < cj> it looks like I could add 'InflateColumn::Object::Enum' to the 
            __PACKAGE__->load_components(...) list for tables with enum 
            columns
15:12 < cj> and then call values() on the enum column
15:13 < cj> but how do I get dbic-dump to add 
            'InflateColumn::Object::Enum' to 
            __PACKAGE__->load_components(...) for only tables with enum 
            columns?
15:20 < cj> I guess I could just add it for all tables, since I'm doing 
            the same for InflateColumn::DateTime
15:39 < cj> hurm... is there a way to get a column without making a 
            request to the db?
15:40 < cj> I know that we store in the DTSS::CDN::Schema::Result::Cdnurl 
            class all of the information that I need to know about the 
            scheme column before any request is issued
15:42 <@ilmari> cj: for Pg and mysql Schema::Loader will add the list of 
                valid values to the ->{extra}->{list} column attribute
15:43 <@ilmari> cj: if you're using some other database that has enums, 
                patches welcome :)
15:43 <@ilmari> or even just a link to the documentation on how to extract 
                the values
15:43 <@ilmari> and a willingness to test if it's not a database I have 
                access to
15:43 < cj> thanks, but I'm using mysql.  if I were using sqlite for this 
            project, I'd probably oblige :-)
15:44 <@ilmari> cj: to add components to only some tables, use 
                result_components_map
15:44 < cj> and is there a way to get at those attributes without making a 
            query?
15:45 < cj> can we do $schema->resultset('Cdnurl') without having it issue 
            a query, for instance?
15:45 <@ilmari> $result_source->column_info('colname')->{extra}->{list}
15:45 < cj> and $result_source is $schema->resultset('Cdnurl') ?
15:45 <@ilmari> dbic never issues a query until you start retrieving the 
                results
15:45 < cj> oh, nice.
15:46 <@ilmari> $schema->source('Cdnurl')
15:46 <@ilmari> the result source is where the result set gets the results 
                from when they are needed
15:47 <@ilmari> names have meanings :)
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top