Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling
 
PerlMonks  

Re: DBIx::Simple

by trs80 (Priest)
on Mar 28, 2002 at 19:06 UTC ( [id://155071]=note: print w/replies, xml ) Need Help??


in reply to DBIx::Simple

Short response: I don't like it.

Long response: I have been using DBI since 1997 and I have on many occasions wanted a simpler manner in which to interact with it. I have made various wrapping routines and what I don't like about the methods you present for the most part are the names and manner which the connects are handled. For me if DBI is to be Simple it needs to have the following: 1) Configurataion file based connect parameters. These are be predefined before a connect is called or they can be loaded if absent at the time a connection is requested. 2) The user should rarely have to explictly interact with the connect statement, individual methods should make the connection when they are called. 3) The names of the methods should state exactly what is being returned, this may increase the length of the name, but it will go a long way in making the script more mantainable.

Here is some code I have been using for some resent development work, it is not production grade, but hopefully illustrates my point. (disproves?)

our %dbh; # by using a hash of connections, each database # can have its own current connection, which allows # for presistent connections and works fine with Apache::DBI # code similar to this has been running in production code # for the last two years with no ill side effects. # dbhandle that is sub dbhandle { my $self = shift; $self->error_to_log("db_access requested"); $self->error_to_log("Request for connect to: " . $self->conf___database . "Host Name: " . $self->conf___dbd_hostname ); if (defined $dbh{$self->conf___database()}) { $self->error_to_log("Used *cached* handle."); return ($dbh{$self->conf___database()}) } else { my $dsn = "dbi:" . $self->conf___dbd_driver . ":" . $self->c +onf___database . ";host=" . $self->conf___dbd_hostname . ";port=" . $self->conf___dbd_port; $dbh{$self->conf___database()} = DBI->connect("$dsn",$self->co +nf___dbd_user,$self->conf___dbd_password, { PrintError => 1, RaiseError => 1, } ) || die $DBI::errstr; # DBI->trace(2,"/tmp/dbitrace.log"); return($dbh{$self->conf___database()}) ; } } sub db_tables { my $self = shift; my @tables = $self->dbhandle->func( '_ListTables' ); return(@tables); } sub db_add_row_to_table { my ($self,$table,$args) = @_; my @place = (); my @field = (); my @value = (); foreach (keys %{$args}) { push @place, '?'; push @field, $_; push @value, $args->{$_}; } my $string = qq[ insert into $table ( ] . join(' ,', @field) . qq[ ) values ( ] . join(' ,', @place) . qq[ ) ]; my $id = $self->db_do($string , \@value ); return ($id); } sub db_do { my ($self,$string,$placeholders) = @_; my $id; $self->error_to_log("$string"); my $cursor = $self->dbhandle->prepare($string); $cursor->execute(@{ $placeholders }); if ($string =~ /^\s?insert/i) { $id = $self->dbhandle->{'mysql_insertid'}; # ($id) = $self->db_row("SELECT MAX(page_id) FROM page"); } return ( $id ); } sub db_disconnect { my $self = shift; my $change = 1; if ($self->dbhandle && $change == 1) { $self->dbhandle->disconnect(); # $self->error_to_log("Disconnected from: $db_to_disco +nnect"); } } sub db_list_of_databases_as_array { my $self = shift; my $drh = DBI->install_driver( $self->conf___dbd_driver() ); my @databases = $drh->func('127.0.0.1', '3306', '_ListDBs'); return(@databases); } sub db_single_column_as_array { my ($self,$sql) = @_; my (@list); my $cursor=$self->dbhandle->prepare("$sql"); $cursor->execute; while ( my ($tmp) = $cursor->fetchrow ) { push @list,$tmp; } $cursor->finish; return(@list); } sub db_single_row_as_array { my ($self,$string,$placeholders) = @_; $self->error_to_log("STRING: $string"); my $cursor = $self->dbhandle->prepare("$string"); $cursor->execute(@{$placeholders}); my @result = $cursor->fetchrow; $cursor->finish; return(@result); } sub db_all_rows_as_arrayref { my ($self,$string) = @_; my $cursor = $self->dbhandle->prepare("$string"); $cursor->execute; my $results = $cursor->fetchall_arrayref; $cursor->finish; return($results); } sub db_one_row_as_hashref { my ($self,$string,$placeholders) = @_; my $cursor = $self->dbhandle->prepare($string); $cursor->execute(@{$placeholders}); my $result = $cursor->fetchrow_hashref; $cursor->finish; return ($result); }

Replies are listed 'Best First'.
DBIx::Connect
by lachoy (Parson) on Mar 28, 2002 at 21:48 UTC

    FWIW: There's a relatively new module on by princepawn to deal with the connection information: DBIx::Connect. It uses AppConfig to store/parse the information but provides a common interface.

    Chris
    M-x auto-bs-mode

      Thanks for the reminder that this module is out there. For applications that will only access a single database this is a simple/good way to keep your connect information external of the code.

      AppConfig had some limitation I couldn't live with. I use XML::Simple since I need some complex datastructures.
Re: Re: DBIx::Simple
by Juerd (Abbot) on Mar 28, 2002 at 20:08 UTC

    1) Configurataion file based connect parameters. These are be predefined before a connect is called or they can be loaded if absent at the time a connection is requested. 2) The user should rarely have to explictly interact with the connect statement, individual methods should make the connection when they are called.

    I disagree completely. Configuration files should not be handled by a module. If the database has to be configurable, the user must provide for a function like that. Another reason I didn't create a dsn myself is that DBI's dsn is already useable, and I'm planning on writing a DSN-generator that uses the PEAR DSN scheme (mysql://user:pass@host/database and like that), so that you can use connect(pear('foo://bar...')).

    OO Modules should NOT require external configuration files, but should get their configuration in the constructor method.

    3) The names of the methods should state exactly what is being returned, this may increase the length of the name, but it will go a long way in making the script more mantainable.

    You're right on that, but "hash" and "array" are acceptable, as a sub CANNOT return a real hash or real array. A sub can return a hash _reference_, or array _reference_. Besides, documentation removes all ambiguity, as the pod is very clear on what is returned.

    That's another thing DBI does wrong: fetchrow_array returns a list, so it should be called fetchrow_list.

    U28geW91IGNhbiBhbGwgcm90MTMgY
    W5kIHBhY2soKS4gQnV0IGRvIHlvdS
    ByZWNvZ25pc2UgQmFzZTY0IHdoZW4
    geW91IHNlZSBpdD8gIC0tIEp1ZXJk
    

      I know you disagree, that is why you did yours differently.
      I am curious, why an OO module should not have an external configuration file. By having a separate configuration file you can access the configuration file from utilities outside of the modules when you are doing something small and other languages can read them if they are in a digestable format. I use the same connect handling mechanism and dynamicly determine which conf to use based on directory location, this avoids be from having to hard code anything inside of the modules themsevles, which I thought was the real point in OO, not to disallow any external information, but to promote external information for configuration and settings. The code I have allows for BOTH from a configuration file and setting the parameters inside of the application. Here is a trimed down constructor I am using in a current project.

      sub new { my ($class) = @_; my $self = {}; bless $self , $class; my $config = { dbd_user => 'user', dbd_driver => 'mysql', title_text => 'TITLE HERE', database => 'my_database', dbd_port => '3306', style_sheet => 'default.css', dbd_password => 'my_pass', smtp_server => 'mytrusted.mailserver.com', dbd_hostname => '127.0.0.1' }; $self->_debug(1); $self->assign_to_object('conf',$config); # $self->error_to_log(Dumper($self)); return $self; } sub assign_to_object { my ($self,$prefix,$hash) = @_; foreach my $column (keys %{$hash}) { my $method = "$prefix" . "___" . "$column"; $self->$method($hash->{$column}); } }
      This is all part of a much larger framework that I am still refining. I some of this makes no sense unless you know more about the rest of the framework, I will have to save that for another post.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://155071]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others studying the Monastery: (2)
As of 2024-04-25 23:04 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found