Vague thoughts about is_a and might_be relationships

[prev] [thread] [next] [Date index for 2004/08/18]

From: Tom Hukins
Subject: Vague thoughts about is_a and might_be relationships
Date: 14:22 on 18 Aug 2004
I've been thinking about how Class::DBI might work with table
inheritance recently and briefly experimented with writing a custom
relationship for this.  This is partly a feature request, and partly an
attempt to document what I've done so far.

Imagine I have a group of pets.  My pets may be cats or dogs.

I could model this scenario in SQL roughly as follows:
  CREATE TABLE cats (
    id          INTEGER PRIMARY KEY,
    name        VARCHAR(255),
    owner       INTEGER,
    basket      INTEGER
  );
  CREATE TABLE dogs (
    id          INTEGER PRIMARY KEY,
    name        VARCHAR(255),
    owner       INTEGER,
    kennel      INTEGER
  );

And with Class::DBI as follows:
  package Pet::Cat;
  use base 'Class::DBI::SQLite';

  __PACKAGE__->set_up_table('cats');
  __PACKAGE__->has-a(owner  => 'Person');
  __PACKAGE__->has_a(basket => 'House::Basket');

  package Pet::Dog;
  use base 'Class::DBI::SQLite';

  __PACKAGE__->set_up_table('dogs');
  __PACKAGE__->has-a(owner  => 'Person');
  __PACKAGE__->has_a(kennel => 'House::Kennel');

This works fine, but if I want to retrieve a list of all the pets I own,
I need to know all the classes that represent pets.

I would like to do something like:
  CREATE TABLE pets (
    id          INTEGER PRIMARY KEY,
    name        VARCHAR(255),
    owner       INTEGER
  );
  CREATE TABLE cats (
    id          INTEGER PRIMARY KEY,
    basket      INTEGER
  );
  CREATE TABLE dogs (
    id          INTEGER PRIMARY KEY,
    kennel      INTEGER
  );

  package Pet;
  use base 'Class::DBI::SQLite';

  __PACKAGE__->set_up_table('pets');
  __PACKAGE__->might_be('Pet::Cat');
  __PACKAGE__->might_be('Pet::Dog');

  package Pet::Cat;
  use base 'Class::DBI::SQLite';

  __PACKAGE__->set_up_table('cats');
  __PACKAGE__->is_a('Pet');

  # Pet::Dog works the same way as Pet::Cat

The new things here are the is_a and might_be relationships.  These
specify inheritance but do so in a non-Perlish way:  We don't 'use base'
for inheritance to avoid set_up_table and relationship specification
methods being called twice.  I think this makes sense.

The existing might_have relationship works very much like how I imagine
might_be working.  I wonder if it lacks anything.

The is_a relationship would behave somewhat like a cross between has_a
and might_have.  If an object exists in the subclass (eg.  Pet::Cat) it
must also exist in the superclass (Pet), as per a has_a relationship.
However, I imagine is_a having a 'methods' method like might_have's:
allowing direct access to superclass attributes, eg.  $cat->name instead
of $cat->id->name.

Also, when using the subclass's create method, eg. Pet::Cat->create, the
underlying Pet information must be created first, to ensure a
one-to-one mapping between id fields.

Finally, it would be neat if Pet objects were reblessed (using a select
trigger?) into a subclass if appropriate.  If I run:
  my @pets = Pet->retrieve_all;
  print $_->name, ' is a ', ref($_), ".\n" foreach @pets;
I would expect output like:
  Tiddles is a Pet::Cat
  Fido is a Pet::Dog
  Bubbles is a Pet
where pets that don't belong in any subclass aren't reblessed.

Does any of this sound sensible?  Have I missed anything?  Does anyone
have useful advice on relationships that might help me?  In a Class::DBI
context, of course.  Ahem.

Thanks,
Tom

Vague thoughts about is_a and might_be relationships
Tom Hukins 14:22 on 18 Aug 2004

is_a relationship?
Caroline Johnston 14:14 on 27 Aug 2004

Generated at 11:34 on 01 Dec 2004 by mariachi v0.52