Tim,
I spoke to you briefly at the OSCON last week during the Perl
Lightning Talks (I gave one on SQL::Translator). Though I didn't
raise my hand when you asked for people to contribute to a DBI module
for Perl 6, I've had some ideas that I thought about sharing. Part of
what I'm thinking is based on the "7 Principles of Better API Design"
tutorial I heard Damian give earlier in the week. There he made a
point that a great place to start designing a module is to first
decide how you want to use/call it, and I definitely agree with that.
So I thought I might send you some ideas about P6 DBI API.
1) I respectfully submit to use "new" instead of "connect" to
instantiate a connection.
And since I always include "{ RaiseError => 1 }," I would request that
this argument be the default and that someone would have to turn this
off explicitly.
I would also like to see the DSN change since they all start with
"dbi:" -- couldn't that be left off, then? I would also love to see
some standardization on the driver names ("mysql" when it's normally
written "MySQL," "Pg" when the db is called "PostgreSQL," etc.).
Also, WRT there being "no standard for the text following the driver
name," perhaps there should be?
use DBI;
my $dbh = DBI.new( driver => 'MySQL', dsn =>
'host=cabot;database=markers30', user => 'web_ro' ... );
2) Damian harped on having to write things on every call, and I have
definitely found the middle hashref arg to most DBI calls to be
irksome as for me using MySQL/Pg/SQLite almost all my Perl career,
I've only ever passed "{}" (except for "{ Columns => {} }" on
"selectall_arrayref"). So I'd love to see that arg go away, and I'm
assuming that with P6 sub prototypes that you won't have to worry so
much about positional args and can get rid of that anyway. Perhaps
all the args should be named, which is particularly easy with the new
pair syntax:
my $data = $dbh.selectcol_arrayref( :$sql, :@args, :%option );
3) Another thing I'd like to suggest is a wholesale revamp of the
method names with an eye towards throwing out most of them, or, if not
that, then adding a new method that uses something like
Contextual::Return's ability to figure out the right thing to return:
my @data = $dbh.get( :$sql ); # returns an array
my $iter = $dbh.get( :$sql ); # returns an iterator
Likewise, each member of the array or iterator could be polymorphic
depending on how it's used.
for my $obj ( @data ) {
print $obj.{'foo'};
print $obj.[0];
}
4) In addition to getting rows back as array/hash refs, perhaps add an
object interface either that uses (santized) column names as (read-
only) accessors or has a general-purpose accessor. The idea here is
to throw an exception when someone requests a non-existent column:
my $sql = 'select foo, bar from baz';
my $iter = $dbh.get( :$sql );
while ( my $rec = $iter.next ) {
my $foo = $rec.foo;
my $bar = $rec.value('bar');
my $q1 = $rec.quux; # exception as there is no "quux" selected
my $q2 = $rec.value('quux'); # another exception
}
I added something like this in my Text::RecordParser module:
http://search.cpan.org/dist/Text-RecordParser/lib/Text/RecordParser/Object.pm
That's all I can think of for now.
ky