+use strict;
+use warnings;
package DBIx::Class::ResultSet::RecursiveUpdate;
-use version; $VERSION = qv('0.002');
+use version; our $VERSION = qv('0.004');
-use warnings;
-use strict;
+use base qw(DBIx::Class::ResultSet);
+
+sub recursive_update {
+ my ( $self, $updates, $fixed_fields ) = @_;
+ return DBIx::Class::ResultSet::RecursiveUpdate::Functions::recursive_update(
+ resultset => $self,
+ updates => $updates,
+ fixed_fields => $fixed_fields
+ );
+}
+
+package DBIx::Class::ResultSet::RecursiveUpdate::Functions;
use Carp;
use Scalar::Util qw( blessed );
-use base qw(DBIx::Class::ResultSet);
sub recursive_update {
- my ( $self, $updates, $fixed_fields ) = @_;
+ my %params = @_;
+ my ( $self, $updates, $fixed_fields, $object ) = @params{ qw/resultset updates fixed_fields object/ };
# warn 'entering: ' . $self->result_source->from();
-
carp 'fixed fields needs to be an array ref' if $fixed_fields && ref($fixed_fields) ne 'ARRAY';
my %fixed_fields;
%fixed_fields = map { $_ => 1 } @$fixed_fields if $fixed_fields;
-
if ( blessed($updates) && $updates->isa('DBIx::Class::Row') ) {
return $updates;
}
# relations that that should be done after the row is inserted into the database
# like has_many and might_have
my %post_updates;
- my %columns_by_accessor = $self->_get_columns_by_accessor;
+ my %columns_by_accessor = _get_columns_by_accessor( $self );
for my $name ( keys %$updates ) {
my $source = $self->result_source;
my $info = $source->relationship_info($name);
if (
_master_relation_cond(
- $source, $info->{cond}, $self->_get_pk_for_related($name)
+ $source, $info->{cond}, _get_pk_for_related( $self, $name)
)
)
{
}
# warn 'columns: ' . Dumper( \%columns ); use Data::Dumper;
- my $object;
my @missing =
grep { !exists $columns{$_} && !exists $fixed_fields{$_} } $self->result_source->primary_columns;
- if ( !scalar @missing ) {
+ if ( !$object && !scalar @missing ) {
$object = $self->find( \%columns, { key => 'primary' } );
}
$object ||= $self->new( {} );
}
for my $name ( keys %pre_updates ) {
my $info = $object->result_source->relationship_info($name);
- $self->_update_relation( $name, $updates, $object, $info );
+ _update_relation( $self, $name, $updates, $object, $info );
}
# $self->_delete_empty_auto_increment($object);
next if exists $columns{$name};
my $value = $updates->{$name};
- if ( $self->is_m2m($name) ) {
- my ($pk) = $self->_get_pk_for_related($name);
+ if ( is_m2m( $self, $name) ) {
+ my ($pk) = _get_pk_for_related( $self, $name);
my @rows;
my $result_source = $object->$name->result_source;
for my $elem ( @{ $updates->{$name} } ) {
}
for my $name ( keys %post_updates ) {
my $info = $object->result_source->relationship_info($name);
- $self->_update_relation( $name, $updates, $object, $info );
+ _update_relation( $self, $name, $updates, $object, $info );
}
return $object;
}
sub _update_relation {
my ( $self, $name, $updates, $object, $info ) = @_;
-
my $related_result =
$self->related_resultset($name)->result_source->resultset;
my $resolved =
for my $sub_updates ( @{ $updates->{$name} } ) {
$sub_updates = { %$sub_updates, %$resolved } if $resolved && ref( $sub_updates ) eq 'HASH';
my $sub_object =
- $related_result->recursive_update( $sub_updates );
+ recursive_update( resultset => $related_result, updates => $sub_updates );
}
}
else {
my $sub_updates = $updates->{$name};
$sub_updates = { %$sub_updates, %$resolved } if $resolved && ref( $sub_updates ) eq 'HASH';
my $sub_object =
- $related_result->recursive_update( $sub_updates );
+ recursive_update( resultset => $related_result, updates => $sub_updates );
$object->set_from_related( $name, $sub_object );
}
}
}
# many to many case
- if ( $self->is_m2m($relation) ) {
- $result_source = $self->get_m2m_source($relation);
+ if ( is_m2m($self, $relation) ) {
+ $result_source = get_m2m_source($self, $relation);
}
return $result_source->primary_columns;
}
=head1 NAME
-DBIx::Class::ResultSet::RecursiveUpdate - like update_or_create - but recursive
+DBIx::Class::ResultSet::RecursiveUpdate - like update_or_create - but recursive
=head1 VERSION
-This document describes DBIx::Class::ResultSet::RecursiveUpdate version 0.001
+This document describes DBIx::Class::ResultSet::RecursiveUpdate version 0.004
=head1 SYNOPSIS
+The functional interface:
+
+ my $new_item = DBIx::Class::ResultSet::RecursiveUpdate::Functions::recursive_update({
+ id => 1,
+ owned_dvds => [
+ {
+ title => 'One Flew Over the Cuckoo's Nest'
+ }
+ ]
+ }
+ );
+
+
+As ResultSet subclass:
+
__PACKAGE__->load_namespaces( default_resultset_class => '+DBIx::Class::ResultSet::RecursiveUpdate' );
in the Schema file (see t/lib/DBSchema.pm). Or appriopriate 'use base' in the ResultSet classes.
=head1 DESCRIPTION
-This is the first release - so treat it as experimental.
+This is still experimental. I've added a functional interface so that it can be used
+in Form Processors and not require modification of the model.
You can feed the ->create method with a recursive datastructure and have the related records
created. Unfortunately you cannot do a similar thing with update_or_create - this module
sub run_tests{
my $schema = shift;
- plan tests => 27;
+ plan tests => 28;
my $dvd_rs = $schema->resultset( 'Dvd' );
my $user_rs = $schema->resultset( 'User' );
ok ( $onekey, 'Onekey created' );
ok ( $schema->resultset( 'Twokeys_belongsto' )->find( { key1 => $onekey->id, key2 => 1 } ), 'Twokeys created' );
-
+ is ( $dvd->name, 'Test name', 'Dvd name set' );
# changing existing records
my $num_of_users = $user_rs->count;
$updates = {
id => $dvd->id,
aaaa => undef,
- name => 'Test name',
+ name => undef,
tags => [ ],
'owner' => $another_owner->id,
current_borrower => {
$dvd = $dvd_rs->recursive_update( $updates );
is ( $schema->resultset( 'User' )->count, $initial_user_count + 1, "No new user created" );
- is ( $dvd->name, 'Test name', 'Dvd name set' );
+ is ( $dvd->name, undef, 'Dvd name deleted' );
is ( $dvd->owner->id, $another_owner->id, 'Owner updated' );
is ( $dvd->current_borrower->name, 'new name a', 'Related record modified' );
is ( $dvd->tags->count, 0, 'Tags deleted' );