Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"
 
PerlMonks  

Re^5: Auto-Increment and DBD Agnosticism

by stvn (Monsignor)
on Jun 24, 2004 at 14:15 UTC ( [id://369368]=note: print w/replies, xml ) Need Help??


in reply to Re^4: Auto-Increment and DBD Agnosticism
in thread Auto-Increment and DBD Agnosticism

It feels odd because in the case of Query and ResultSet you have the .pm files living somewhere simply because of namespacing,

Maybe that is not the best place to put Query and ResultSet then? If I were to guess, I would have thought they were more kind of like "inner-classes", meaning classes that Object used internally, OR that they were subclasses of Object. However, if they are actually on the same "level" as Object, I would recommend mimicing that in your directory/namspace structure. Keep in mind that you are adding a top level namespace Whatever::, which maybe can hold Object, Query and ResultSet for you?

Is it right for me to feel that this would be weird, or is this the standard way to it?

Trust your feelings young skyknight. Maybe you should try lowering the blast sheild. A true Perl Jedi does not need his eyes :P

Oh yeah, and no, there is no standard way of doing it, at least that anyone has told me :)

The only alternative that I can fathom would be to put the MySQL class definition inside the Object.pm file.

Yuk. Besides this will only temporarily solve your problem since someday you (or someone else) will need to write a PostgreSQL/Oracle/MSSQLServer/etc subclass for this and you will have to deal with it then.

Now, based on my still limited knowledge of your code, I would suggest moving Query and ResultSet up to the root namespace (since as you say they are only in Object for the namespace). This will allow you to easily place all subclasses in subdirectories. And while right now all you can see a need for subclassing is Object, you never know if at some point you may need to subclass Query or ResultSet as well. Doing it this way leaves that door open just in case.

lib/ Whatever/ Object.pm Object/ MySQL.pm PostgreSQL.pm Oracle.pm Query.pm Query/ MySQL.pm Oracle.pm ResultSet.pm ResultSet/ Interbase.pm

-stvn

Replies are listed 'Best First'.
Re^6: Auto-Increment and DBD Agnosticism
by skyknight (Hermit) on Jun 24, 2004 at 15:14 UTC
    Maybe that is not the best place to put Query and ResultSet then? If I were to guess, I would have thought they were more kind of like "inner-classes", meaning classes that Object used internally, OR that they were subclasses of Object. However, if they are actually on the same "level" as Object, I would recommend mimicing that in your directory/namspace structure. Keep in mind that you are adding a top level namespace Whatever::, which maybe can hold Object, Query and ResultSet for you?

    They are not really suited to being inner classes. Users create and use them directly. If you want to query a collection of objects, you create an instance of Whatever::Object::Query, and invoke its execute method, which returns an instance of Whatever::Object::ResultSet. You then repeatedly invoke that object's get_next_result method which returns instances of Whatever::Object subclasses.

    At first glance, your suggestion to put Query and ResultSet at the top level sounds good, but upon looking at my larger collection of classes, you'll realize that there is a snag. I also have Whatever::Link, Whatever::Link::Query, and Whatever::Link::ResultSet. These two objects are used in two scenarios: you have an object and want to do lazy loading of relatives at some point after it was loaded; you are loading a large collection of objects and want them loaded with one or more sets of relatives so as to keep the number of queries down.

    I suppose I could bring these things top-level by squashing their namespaces, e.g. Whatever::Object::Query becomes Whatever::ObjectQuery and Whatever::Link::Query becomes Whatever::LinkQuery. I don't like that, though...

    Now that I think about it, maybe I have the components of my name spacing all backwards! This all might make a lot more sense if instead of Whatever::Link::Query and Whatever::Object::Query I had Whatever::Query::Link and Whatever::Query::Object. In fact, I think that's perfect... Each of those could probably benefit (though I'm not yet sure how) from a common Whatever::Query base class. Furthermore, I could then use the Object subdirectory strictly for subclasses of Whatever::Object. This fixes all of my quandaries.

    Now, however, I've thought of a problem that I'm going to encounter when trying to make DBD specific subclasses of Whatever::Object, e.g. Whatever::Object::MySQL. The general paradigm of my system already involves users creating subclasses of Whatever::Object, with the stipulation that the subclass provides a get_table_name method which is used both for for schema querying and object loading/saving. For example, if you wanted to have a Foo object, you'd have something like...

    package Foo; use strict; use base qw/Whatever::Object/; # decorator methods go here 1;

    ... and to create a Foo object you would just do

    my $foo = new Foo();

    ... which would cause the "new" method in Whatever::Object to be invoked which would bless a thingy into class Foo.

    As you can probably see by now, this makes things a little sticky... If I'm running in a MySQL environment, then what I really want Foo to be subclassing is Whatever::Object::MySQL, but certainly Foo should be DBD agnostic, knowing only about Whatever::Object and not its DBD specific subclasses. The only thing that jumps to mind right now is to have Whatever::Object::new to go ahead and bless the thingy into Foo, but to also reach into Foo's namespace and mangle its ISA array to have not Whatever::Object, but Whatever::Object::MySQL (or whatever DBD we're using). Am I crazy for even considering this? Is there a more elegant way of doing what I want to do?

      Now that I think about it, maybe I have the components of my name spacing all backwards! This all might make a lot more sense if instead of Whatever::Link::Query and Whatever::Object::Query I had Whatever::Query::Link and Whatever::Query::Object. In fact, I think that's perfect... Each of those could probably benefit (though I'm not yet sure how) from a common Whatever::Query base class. Furthermore, I could then use the Object subdirectory strictly for subclasses of Whatever::Object. This fixes all of my quandaries.

      I like this the best. Feels good to me :)

      Am I crazy for even considering this?

      Of course you are, but that shouldnt surprise you, no doubt you have been crazy all your life, otherwise you wouldnt be a perl programmer :)

      Is there a more elegant way of doing what I want to do?.

      Well, I have had to solve this problem in particular myself, and I always kind of liked the way I did it. I has worked for me quite successfully for a little while now. Here is an example using your namespace:

      package Whatever::Object::DBDAgnostic; use strict; use warnings; sub import { # only set this once return if scalar @Whatever::Object::DBDAgnostic::ISA; my (undef, $base_class) = @_; die "You must define a DBD-type" unless $base_class; push @Whatever::Object::DBDAgnostic::ISA => $base_class; } 1;
      Then all your users need to do is:
      package Foo; use strict; use base qw/Whatever::Object::DBDAgnostic/; # decorator methods go here 1;
      Then in order to set what DBD subclass is to be used you, all your user needs to do this:
      use Whatever::Object::DBDAgnostic qw(Whatever::Object::MySQL);
      Before any other code that uses Whatever::Object::DBDAgnostic is loaded, and your Whatever::Object::DBDAgnostic::ISA should be good. Sure its an extra level of inheritence, but it pays for itself in flexibility. Also keep in mind that perl's method caching will pretty much make a performance cost to null in a long running system like mod_perl.

      -stvn

Log In?
Username:
Password:

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

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

    No recent polls found