[Dbix-class] Dealing with relationships of non-order sensitive value pairs

Guillermo Roditi groditi at gmail.com
Tue Feb 5 08:19:35 GMT 2008


Hey everyone.

I am dealing with a situation where I have a relationship between a
table and itself representing a connection between two items. This is
analogous to a "friend of" relationship, but since relationships must
be two-ways in my application they are not order sensitive. Now, i
understand that to fetch all related objects (B) from an object (A) I
can simply order the PKs and search enforcing that order. It's a
simple solution, it works, but I don't trust future users of my
application to not be morons, so I came up with the Following
solution, I'd like some input from people who have dealt with this in
the past because I know someone out there already hit an issue I
didn't think about or made the the same mistakes I am making or is
just p[lain smarter


I am working on a DBIx::Class-backed DJabberd system with a Catalyst /
Reaction front end and here's the basic explanation of my issue:

Table vhosts has a store of all my DJabbed vhosts and they all have a
numeric PK (i know the name could be a natural key, but i like numeric
IDs sometimes)

My vhost_bridges table has two fields vhost_1_id and vhost2_id which
represent vhosts which are allowed to talk to each other. Because I am
only dealing with two way relationships there is no difference between
vhost1 and vhost2. In order to fetch all bridged hosts I am using the
following sub in lieu of a relation. The rest of the code follows.
what does everyone think and can anyone give me a better way to deal
with this?

#the project JUST got started so there's not much code, but
#what is done of the code is available at:
http://code.google.com/p/cantella-djabberd/source/browse/trunk/lib/Cantella/DJabberd/


sub bridged_hosts{
  my $self = shift;
  my $schema = $self->result_source->schema;
  my $rs = $schema->resultset('VhostBridge');
  my $id = $self->id;
  my @ids = grep{ $_ != $id } map{$_->vhost1_id, $_->vhost1_id}
    $rs->search({ -or =>[ vhost1_id => $id,  vhost2_id => $id ]})->all;
  my $result = $schema->resultset('Vhost')->search_rs({id => {-in => \@ids}});
  return @_ > 0 ? $result->search_rs(@_) : $result;
}


#Full code below:

package Cantella::DJabberd::Schema::Vhost;

use strict;
use warnings;

use base 'DBIx::Class';

__PACKAGE__->load_components("Core");
__PACKAGE__->table("vhosts");
__PACKAGE__->add_columns
  (
   id       => {
                data_type => "INT",
                size => 10,
                default_value => undef,
                is_nullable => 0,
                is_auto_increment => 1,
                extra => { unsigned => 1 },
               },
   hostname => {
                data_type => "VARCHAR",
                size => 255,
                default_value => "",
                is_nullable => 0,
               },
  );

__PACKAGE__->set_primary_key("id");
__PACKAGE__->add_unique_constraint(hostname => ["hostname"]);

__PACKAGE__->has_many
  (
   external_components => "Cantella::DJabberd::Schema::ExternalComponent",
   { "foreign.vhost_id" => "self.id" },
  );

sub bridged_hosts{
  my $self = shift;
  my $schema = $self->result_source->schema;
  my $rs = $schema->resultset('VhostBridge');
  my $id = $self->id;
  my @ids = grep{ $_ != $id } map{$_->vhost1_id, $_->vhost1_id}
    $rs->search({ -or =>[ vhost1_id => $id,  vhost2_id => $id ]})->all;
  my $result = $schema->resultset('Vhost')->search_rs({id => {-in => \@ids}});
  return @_ > 0 ? $result->search_rs(@_) : $result;
}


1;


package Cantella::DJabberd::Schema::VhostBridge;

use strict;
use warnings;

use base 'DBIx::Class';

__PACKAGE__->load_components("Core");
__PACKAGE__->table("vhost_bridges");
__PACKAGE__->add_columns
  (
   vhost1_id => {
                 data_type => "INT",
                 size => 10,
                 default_value => "",
                 is_nullable => 0,
                 extra => { unsigned => 1 },
                 is_foreign_key => 1,
                },
   vhost2_id => {
                 data_type => "INT",
                 size => 10,
                 default_value => "",
                 is_nullable => 0,
                 extra => { unsigned => 1 },
                 is_foreign_key => 1,
                },
  );

__PACKAGE__->set_primary_key("vhost1_id", "vhost2_id");

--Guillermo Roditi (groditi)



More information about the DBIx-Class mailing list