On 1/11/06 9:16 AM, Scott Karns wrote:
> My current problem is that the database I'm working with contains two column
> types that are specific to postgres and don't seem to be supported by RDBO.
> The first I alluded to in an earlier message, the 'OID' column type that I am
> using to store what amounts to blob data (an image file actually)

You can't just use a scalar column for that?  What kind of special handling
does it need?

> and the second is a 'time' column type used to store class (as in school)
> scheduling information. [...] After looking through some of the RDBO::Metadata
> space, I believe my best bet is to create a new scalar column class that will
> convert the Pg data to an integer upon access and back to the Pg form upon
> store as well as some ability to play well with timestamp objects.

I had Pg time types in a few early versions of RDBO, but I could never
decide on a nice client-side representation.  An integer seems like a
strange choice to me.  DateTime objects aren't really appropriate because
time columns have no date information.  I could just make one myself, I
suppose.  What I'm looking for is pretty simple:

* Stringifies to an arbitrary strftime-like format (HH:MM:SS by default)
* Has hour, minute, second, nanosecond, am/pm get/set methods.
* Supports simple time math with wrap-around.

Is such a thing lurking on CPAN anywhere?  Remember, no dates! :)

Anyway, although I'd prefer it if you created a new column class and method
maker for a Time type as I describe above and then submitted it as a patch,
here are two ways you might do what you describe instead (using an integer
as the client-side representation.)

The first option, as Svilen pointed out, is to use triggers.  This will
work, but it maybe tedious to apply those triggers to each of your time
columns in each class.

A more general solution is to make your own column class.  The steps would
be something like this:

1. Make your column class, e.g., My::DB::Column::PgTime.  Inheriting from
the Scalar column class is probably fine.

2. Map your column class to the column type name of your choice, either
globally in Rose::DB::Object::Metadata, or locally in a metadata subclass of
your own.

I'm assuming you already have a common base class for all your db objects.
If so, making a trivial custom metadata subclass and then setting your
common base class's meta_class to this class name should be easy.  You can
see an example of setting up a custom metadata class here:

http://search.cpan.org/dist/Rose-DB-Object/lib/Rose/DB/Object/ConventionMana
ger.pm#TIPS_AND_TRICKS

Either way, to make the mapping, use the column_type_class() method:

http://search.cpan.org/dist/Rose-DB-Object/lib/Rose/DB/Object/Metadata.pm#co
lumn_type_class 

Example:

    $meta->column_type_class(mypgtime => 'My::DB::Column::PgTime');

3. Make a new method-maker for your column class that does the appropriate
inflate/deflate stuff at the right times.  The 'bitefield' method maker in
Rose::DB::Object::MakeMethods::Generic is probably the simplest existing
example.

One caveat: you should definitely use the functions in
Rose::DB::Object::Util to determine when you're save()ing, when you're
load()ing, etc.  The column classes bundled with RDBO use the undocumented
internal methods to get this info (direct hash key access!)  Don't do that
in your classes since that's an implementation detail that may change at any
time.  When it does, RDBO itself will be updated, of course, but your custom
column class will stop working.  So remember: use public APIs only! :)

Anyway, for details on how method makers work, check these docs:

http://search.cpan.org/dist/Rose-Object/lib/Rose/Object/MakeMethods.pm

4. Point your column class at your new method maker.  See the "protected
API" for columns for an easy way to this:

http://search.cpan.org/dist/Rose-DB-Object/lib/Rose/DB/Object/Metadata/Colum
n.pm#PROTECTED_API

5. Finally, when you set up your classes, just use your newly-mapped column
type name:

    __PACKAGE__->meta->columns
    (
      ...
      start => { type => 'mypgtime', ... },
    );

---

Hre's the overall flow inside RDBO starting with a column definition like
the one above.

1. Get type name 'mypgtime' from hashref definition (or column object via
the type() attribute).

2. Look up the corresponding class by calling
$meta->column_type_class('mypgtime') using the metadata object for this
class.

3. Make a new column object of that class, initializing it based on the rest
of the params in the hashref (+/- some massaging)

<...time passes...>

4. Inside the call to meta->initiaize(), make_methods() is called on the
column object in order to make the accessor method(s) to service this
column.  To do this, the column object will call through to a method-maker.

Although, technically, a column can do whatever it wants in response to
make_methods(), RDBO uses Rose::Object::MakeMethods to do the work, and the
Column base class has a bunch of configuration values that make it easy to
point to a particular method maker of that type.

Confused yet? :)  If you really want to tackle it, just start at the
beginning and take it a piece at a time.  Or, if you can wait, then find me
a nice time object on CPAN so I can add a default Time column type to RDBO.
Then wait for the next release and just use that :)

I keep meaning to write Rose::DB::Object::Extending.pod...

-John




-------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc. Do you grep through log files
for problems?  Stop!  Download the new AJAX search engine that makes
searching your log files as easy as surfing the  web.  DOWNLOAD SPLUNK!
http://ads.osdn.com/?ad_id=7637&alloc_id=16865&op=click
_______________________________________________
Rose-db-object mailing list
Rose-db-object@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/rose-db-object

Reply via email to