{ key => 'artist_title' }
);
-See also L</find_or_create> and L</update_or_create>.
+If no C<key> is specified, it searches on all unique constraints defined on the
+source, including the primary key.
+
+If the C<key> is specified as C<primary>, it searches only on the primary key.
+
+See also L</find_or_create> and L</update_or_create>. For information on how to
+declare unique constraints, see
+L<DBIx::Class::ResultSource/add_unique_constraint>.
=cut
my ($self, @vals) = @_;
my $attrs = (@vals > 1 && ref $vals[$#vals] eq 'HASH' ? pop(@vals) : {});
- my @cols = $self->result_source->primary_columns;
+ my %unique_constraints = $self->result_source->unique_constraints;
+ $self->throw_exception(
+ "Can't find unless a primary key or unique constraint is defined"
+ ) unless %unique_constraints;
+
+ my @constraint_names = keys %unique_constraints;
if (exists $attrs->{key}) {
- my %uniq = $self->result_source->unique_constraints;
$self->throw_exception(
"Unknown key $attrs->{key} on '" . $self->result_source->name . "'"
- ) unless exists $uniq{$attrs->{key}};
- @cols = @{ $uniq{$attrs->{key}} };
- }
- #use Data::Dumper; warn Dumper($attrs, @vals, @cols);
- $self->throw_exception(
- "Can't find unless a primary key or unique constraint is defined"
- ) unless @cols;
-
- my $query;
- if (ref $vals[0] eq 'HASH') {
- $query = { %{$vals[0]} };
- } elsif (@cols == @vals) {
- $query = {};
- @{$query}{@cols} = @vals;
- } else {
- $query = {@vals};
+ ) unless exists $unique_constraints{$attrs->{key}};
+
+ @constraint_names = ($attrs->{key});
}
- foreach my $key (grep { ! m/\./ } keys %$query) {
- $query->{"$self->{attrs}{alias}.$key"} = delete $query->{$key};
+
+ my @unique_hashes;
+ foreach my $name (@constraint_names) {
+ my @unique_cols = @{ $unique_constraints{$name} };
+ my %unique_hash;
+ if (ref $vals[0] eq 'HASH') {
+ # Stupid hack for CDBICompat
+ my %hash = %{ $vals[0] };
+ foreach my $key (keys %hash) {
+ $hash{lc $key} = delete $hash{$key};
+ }
+
+ %unique_hash =
+ map { $_ => $hash{$_} }
+ grep { exists $hash{$_} }
+ @unique_cols;
+ }
+ elsif (@unique_cols == @vals) {
+ # Assume the argument order corresponds to the constraint definition
+ @unique_hash{@unique_cols} = @vals;
+ }
+ elsif (@vals % 2 == 0) {
+ # Fix for CDBI calling with a hash
+ %unique_hash = @vals;
+ }
+
+ foreach my $key (grep { ! m/\./ } keys %unique_hash) {
+ $unique_hash{"$self->{attrs}{alias}.$key"} = delete $unique_hash{$key};
+ }
+
+ #use Data::Dumper; warn Dumper \@vals, \@unique_cols, \%unique_hash;
+ push @unique_hashes, \%unique_hash if %unique_hash;
}
- #warn Dumper($query);
-
+
+ # Handle cases where the ResultSet already defines the query
+ my $query = @unique_hashes ? \@unique_hashes : undef;
+
if (keys %$attrs) {
- my $rs = $self->search($query,$attrs);
- return keys %{$rs->{collapse}} ? $rs->next : $rs->single;
- } else {
- return keys %{$self->{collapse}} ?
- $self->search($query)->next :
- $self->single($query);
+ my $rs = $self->search($query, $attrs);
+ return keys %{$rs->{collapse}} ? $rs->next : $rs->single;
+ }
+ else {
+ return keys %{$self->{collapse}}
+ ? $self->search($query)->next
+ : $self->single($query);
}
}
my $cd = $schema->resultset('CD')->single({ year => 2001 });
Inflates the first result without creating a cursor if the resultset has
-any records in it; if not returns nothing. Used by find() as an optimisation.
+any records in it; if not returns nothing. Used by L</find> as an optimisation.
=cut
#
# update/delete require the condition to be modified to handle
# the differing SQL syntax available. This transforms the $self->{cond}
-# appropriately, returning the new condition
+# appropriately, returning the new condition.
sub _cond_for_update_delete {
my ($self) = @_;
my $cond = {};
if (!ref($self->{cond})) {
- # No-op. No condition, we're update/deleting everything
+ # No-op. No condition, we're updating/deleting everything
}
elsif (ref $self->{cond} eq 'ARRAY') {
$cond = [
$hash{$1} = $_->{$key};
}
\%hash;
- } @{$self->{cond}}
+ } @{$self->{cond}}
];
}
elsif (ref $self->{cond} eq 'HASH') {
if ((keys %{$self->{cond}})[0] eq '-and') {
- $cond->{-and} = [
- map {
- my %hash;
- foreach my $key (keys %{$_}) {
+ $cond->{-and} = [];
+
+ my @cond = @{$self->{cond}{-and}};
+ for (my $i = 0; $i < @cond - 1; $i++) {
+ my $entry = $cond[$i];
+
+ my %hash;
+ if (ref $entry eq 'HASH') {
+ foreach my $key (keys %{$entry}) {
$key =~ /([^.]+)$/;
- $hash{$1} = $_->{$key};
+ $hash{$1} = $entry->{$key};
}
- \%hash;
- } @{$self->{cond}{-and}}
- ];
+ }
+ else {
+ $entry =~ /([^.]+)$/;
+ $hash{$entry} = $cond[++$i];
+ }
+
+ push @{$cond->{-and}}, \%hash;
+ }
}
else {
foreach my $key (keys %{$self->{cond}}) {
}
else {
$self->throw_exception(
- "Can't update/delete on resultset with condition unless hash or array");
+ "Can't update/delete on resultset with condition unless hash or array"
+ );
}
+
return $cond;
}
return $obj;
}
+=head2 find_or_new
+
+=over 4
+
+=item Arguments: \%vals, \%attrs?
+
+=item Return Value: $object
+
+=back
+
+Find an existing record from this resultset. If none exists, instantiate a new
+result object and return it. The object will not be saved into your storage
+until you call L<DBIx::Class::Row/insert> on it.
+
+If you want objects to be saved immediately, use L</find_or_create> instead.
+
+=cut
+
+sub find_or_new {
+ my $self = shift;
+ my $attrs = (@_ > 1 && ref $_[$#_] eq 'HASH' ? pop(@_) : {});
+ my $hash = ref $_[0] eq 'HASH' ? shift : {@_};
+ my $exists = $self->find($hash, $attrs);
+ return defined $exists ? $exists : $self->new_result($hash);
+}
+
=head2 create
=over 4
{ key => 'artist_title' }
);
-See also L</find> and L</update_or_create>.
+See also L</find> and L</update_or_create>. For information on how to declare
+unique constraints, see L<DBIx::Class::ResultSource/add_unique_constraint>.
=cut
If the C<key> is specified as C<primary>, it searches only on the primary key.
-See also L</find> and L</find_or_create>.
+See also L</find> and L</find_or_create>. For information on how to declare
+unique constraints, see L<DBIx::Class::ResultSource/add_unique_constraint>.
=cut
my $attrs = (@_ > 1 && ref $_[$#_] eq 'HASH' ? pop(@_) : {});
my $hash = ref $_[0] eq 'HASH' ? shift : {@_};
- my %unique_constraints = $self->result_source->unique_constraints;
- my @constraint_names = (exists $attrs->{key}
- ? ($attrs->{key})
- : keys %unique_constraints);
-
- my @unique_hashes;
- foreach my $name (@constraint_names) {
- my @unique_cols = @{ $unique_constraints{$name} };
- my %unique_hash =
- map { $_ => $hash->{$_} }
- grep { exists $hash->{$_} }
- @unique_cols;
-
- push @unique_hashes, \%unique_hash
- if (scalar keys %unique_hash == scalar @unique_cols);
- }
-
- if (@unique_hashes) {
- my $row = $self->single(\@unique_hashes);
- if (defined $row) {
- $row->set_columns($hash);
- $row->update;
- return $row;
- }
+ my $row = $self->find($hash, $attrs);
+ if (defined $row) {
+ $row->set_columns($hash);
+ $row->update;
+ return $row;
}
return $self->create($hash);