[Dbix-class] coercing Result objects
Dave Howorth
dhoworth at mrc-lmb.cam.ac.uk
Tue Nov 13 14:55:09 GMT 2012
I have an odd setup of Result classes, because I live with an odd
database. There are a bunch of tables that are all very similar but all
a bit different. So I have a bunch of Result classes that directly
reflect each individual table with all its quirks. And I also have an
overarching virtual Result class that makes a view by taking a UNION of
all the tables and extracting the common fields. It all works.
Sometimes, I retrieve a record from one of the tables and need to
convert it to the general form, or I retrieve a record via the
overarching class and need to get the specific form. So the Result
classes have methods that perform this transformation. At the moment,
they do it by doing ->find($id) on a resultset of the appropriate class.
But this isn't very nice because it hits the database again to retrieve
the same data just to wrap it in a different object. And that can be a
performance problem, quite apart from being ugly.
So is there any way to tell DBIC to rewrap the data in different object
clothes without hitting the database each time?
I have one table that looks something like:
package MySchema::Result::Foo;
__PACKAGE__->table("foo");
__PACKAGE__->add_columns(
"cf_id",
{ data_type => "mediumint", is_nullable => 0 },
"cf_name",
{ data_type => "text", is_nullable => 1 },
"cf_comment",
{ data_type => "text", is_nullable => 1 },
"cf_attribute",
{
data_type => "enum",
default_value => "foo",
extra => { list => ["foo", "bar"] },
is_nullable => 0,
},
);
cf_id, cf_name and cf_comment are the same as in all the other tables,
but cf_attribute is unique to this table.
And I have an overarching virtual table that looks like:
package MySchema::Result::Node;
__PACKAGE__->table_class('DBIx::Class::ResultSource::View');
__PACKAGE__->table('nodes');
__PACKAGE__->result_source_instance->is_virtual(1);
__PACKAGE__->result_source_instance->view_definition(
"SELECT
cf_id AS id,
cf_name AS name,
cf_comment AS _comment
FROM foo
UNION
SELECT
... etc for other tables ..."
);
__PACKAGE__->add_columns(
id => {
data_type => 'mediumint',
is_nullable => 0,
},
name => {
data_type => 'text',
is_nullable => 1,
},
_comment => {
data_type => 'text',
is_nullable => 1,
},
);
So given an object $foo that is a MySchema::Result::Foo, can I repackage
it as a MySchema::Result::Node without going back to the database? And
without hand-coding it all? I think something like this ought to work,
but I'd rather not have to reinvent it if it already exists:
package MySchema::Result::Foo;
sub node {
my $foo = shift;
my $schema = $foo->result_source->schema;
my $node_rs = $schema->resultset('Node');
my $node = $node_rs->new_result({
id => $foo->cf_id,
name => $foo->cf_name,
_comment => $foo->cf_comment,
});
return $node;
}
or maybe
sub node {
my $foo = shift;
my $node = MySchema::Result::Node->new({
id => $foo->cf_id,
name => $foo->cf_name,
_comment => $foo->cf_comment,
result_source => $foo->result_source,
});
return $node;
}
More information about the DBIx-Class
mailing list