Beefy Boxes and Bandwidth Generously Provided by pair Networks vroom
Perl Monk, Perl Meditation
 
PerlMonks  

Database abstraction including data types

by mbethke (Hermit)
on May 20, 2012 at 16:22 UTC ( #971496=perlquestion: print w/ replies, xml ) Need Help??
mbethke has asked for the wisdom of the Perl Monks concerning the following question:

There's heaps of database abstraction modules in Perl but it seems that while abstraction always means "You don't have to deal with messy C interfaces", and sometimes "You can write SQL in Perl", it hardly ever means "we'll take care of data type idiosyncrasies for you". I need something like that.

My problem (briefly mentioned in my announcement of Ashafix) is this: I've used a couple of DBMS layers but all programs have been tied to one particular DBMS. Now I want to write one that runs unchanged on at least PostgreSQL and MySQL and my first problem is the handling of booleans. Pg uses an own type that returns 't' or 'f' while MySQL by convention uses TINYINT that is set to zero or non-zero. Currently I'm using DBIx::Simple and I'd prefer to keep it fairly slim. My ideas so far:

  • Define an ENUM in MySQL to emulate the Pg behavior. Doesn't work because other software is using the database too and would get very confused.
  • Use DBIx::Class, write my own InflateColumn::Bool and a primitive Bool class that uses a tied hash or something to give the usual zero-or-nonzero-scalar behavior when used in boolean context.
    Disadvantage: that's about as fat as it gets.
  • Subclass DBIx::Simple, feed it a simple column=>type mapping for each table I'll use and make all retrieval methods use a hash()/hashes() method internally so I can do the mapping myself.
    Disadvantage: smells inefficient (although it's probably still much faster than DBIx::Class), may be reinventing the wheel.

Have I by any chance overlooked something on CPAN that would let me do this in a simpler way?

Comment on Database abstraction including data types
Re: Database abstraction including data types ( $dbh->{pg_bool_tf} )
by erix (Priest) on May 20, 2012 at 19:49 UTC

    Hardly a complete answer, but handy for the particular true/false problem that you mention is, for the postgres side: $dbh->{pg_bool_tf}, which lets you choose between t/f or 1/0:

    $ perl -Mstrict -MDBI -E 'my$dbh=DBI->connect("dbi:Pg:"); $dbh->{pg_bool_tf} = 0; # true false is now 1/0 print $dbh->selectall_arrayref("select 1=1")->[0]->[0], "\n"; $dbh->{pg_bool_tf} = 1; # true false is now t/f print $dbh->selectall_arrayref("select 1=1")->[0]->[0], "\n"; # ' output: 1 t

    (See DBD::Pg $dbh attributes.)

      Aternatively do it all in the database:

      SELECT CASE WHEN column_name THEN 1 ELSE 0 END AS column_name FROM table ...
        By the way, that whole app looks like a good candidate for SQLite which could simplify the configuration and management a bit.

      Now that's cool, hadn't even thought that it could have been abstracted on such a low level. That may just be enough for this particular application unless I run into other incompatibilities, which looks unlikely. Thank you!

Re: Database abstraction including data types
by sundialsvc4 (Monsignor) on May 20, 2012 at 22:43 UTC

    First of all, I don’t “abstract away” a database too much.   I am probably going to write the application against a single database platform such that I probably will never change it.   (If I did, I would select DBIx::Class.)

    What I am going to abstract-away is anything that cares what the particular column-name is; whether some business fact is captured by value x occurring in column y of table z.   I really want there to be just one piece of software in my application that “has to know” this.

    Because, you know, if my code is littered with many copies of logic that queries the customer table and queries customer_type and checks for the value 'SC' to determine that the customer is a senior-citizen ... the true bugaboo is not precisely how I said that all those different times, but rather that I said it so many times in so many places.   That is what’s going to blossom into a maintenance problem that’s gonna bite me in the asterisk, no matter how exactly I said it.   A database table is not a business object.   You need to heavily and constantly focus your attentions on:   “what determinations are made, not how they are expressed in the current data model.”

    to determine that the customer is a senior-citizen ... the true bugaboo is not precisely how I said that all those different times, but rather that I said it so many times in so many places.

      I agree completely; "DB abstraction layer" is just a fancy term for that piece of centralized code that speaks SQL to the database and business objects to the rest. The original coughphpcough code has just the problem you mentioned: it needs to know which column is a boolean and treat that specially in quite a lot of places to account for MySQL vs. PostgeSQL differences, and I don't want to go there.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://971496]
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others scrutinizing the Monastery: (6)
As of 2014-04-20 02:03 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    April first is:







    Results (485 votes), past polls