Another patch is attached - have a look and discuss.  It's becoming
more and more complicated and perhaps the alternative would be
simpler.

cheers,
Z.

On Jan 16, 2008 1:29 PM, Zbigniew Lukasiak <[EMAIL PROTECTED]> wrote:
> On Jan 16, 2008 10:54 AM, Ash Berlin <[EMAIL PROTECTED]> wrote:
> >
> >
> > On Jan 16, 2008, at 9:02 AM, Zbigniew Lukasiak wrote:
> >
> > > Hi all
> > >
> > > This is a continuation of the "patch for ResultSet::find_or_new"
> > > thread - but it's also a subject on it's own.
> > >
> > > It is my understanding that:
> > >
> > > $schema->resultset("Artist")->find({name => 'Random Girl Band'}, {key
> > > => 'primary'});
> > >
> > > should never find anything - because it should search by the primary
> > > key that is not included in the search conditions.  And I believe I am
> > > not alone in this interpretation of the documentation - see for
> > > example Matt's words:
> > >
> > >> The usual use of find_or_new is to pass a unique key plus additional
> > >> attributes to be used for object creation (which are ignored in the
> > >> find()
> > >> by specifying the key attr as well).
> > >
> > > But if there is a row with name == 'Random Girl Band' then it will
> > > find it.  To prove that I attach a patch for the  t/61findnot.t test.
> > >
> > > --
> > > Zbigniew Lukasiak
> > > http://brudnopis.blogspot.com/
> > > <61findnot.diff>_______________________________________________
> > >
> >
> > Seems sensible to me - the patch shows the behaviour I would *expect*.
>
> OK.  Patch is attached - perhaps someone would instruct me what would
> be the right way to specify the 'FALSE' condition for the query.
>
> But after having done that patch I think that this is actually a very
> corner case - and perhaps it is a bug to not include the unique keys
> in the query when you do find and we should not do that.
>
> I've started this investigation because of update_or_create (and
> find_or_create and find_or_new - all of which use the same logic).
> They are useful in the case when you receive back some fields from a
> web form and you want to use the same code for updating an existing
> record and creating a new one.  But when you do find_or_create( {
> primary_key => undef, other_col => 'some value', ... } ) then it will
> fail in PostgreSQL and the answer was to do find_or_create( {other_col
> => 'some value', ... } ) and, as the test case shows, this was failing
> to do the right thing either so I was stuck.
>
> An alternative could be to insert DEFAULT by the PostgreSQL storage if
> the primary key inserted is NULL (MySQL and SQLite would work fine
> with inserting a NULL pk).
>
> I don't know - all I wanted was a working update_or_create method.
>
> --
> Zbigniew Lukasiak
> http://perlalchemy.blogspot.com/
>



-- 
Zbigniew Lukasiak
http://brudnopis.blogspot.com/
Index: t/61findnot.t
===================================================================
--- t/61findnot.t	(revision 3948)
+++ t/61findnot.t	(working copy)
@@ -7,7 +7,7 @@
 
 my $schema = DBICTest->init_schema();
 
-plan tests => 17;
+plan tests => 20;
 
 my $art = $schema->resultset("Artist")->find(4);
 ok(!defined($art), 'Find on primary id: artist not found');
@@ -44,3 +44,15 @@
 @cd = $cd->single;
 cmp_ok(@cd, '==', 1, 'Return something even in array context');
 ok(@cd && !defined($cd[0]), 'Array contains an undef as only element');
+
+my $random_girl = $schema->resultset("Artist")->create({ name => 'Random Girl Band'});
+$art = $schema->resultset("Artist")->find({name => 'Random Girl Band'}, {dont_fallback => 1});
+ok(!defined($art), 'Find on primary key with no key provided: artist not found');
+
+my $random_again = $schema->resultset("Artist")->search( artistid => $random_girl->id )->find({}, {dont_fallback => 1});
+ok(defined($random_again), 'Find on primary key with no key provided on a narrow resultset: record found');
+
+$cd = $schema->resultset("CD")->first;
+$art = $cd->find_related( 'artist', {}, {dont_fallback => 1} );
+ok( defined $art, 'find_related for a belongs_to relation traversed' );
+
Index: lib/DBIx/Class/ResultSet.pm
===================================================================
--- lib/DBIx/Class/ResultSet.pm	(revision 3948)
+++ lib/DBIx/Class/ResultSet.pm	(working copy)
@@ -321,6 +321,11 @@
 If no C<key> is specified, it searches on all unique constraints defined on the
 source, including the primary key.
 
+If you specify columns explicitely and there are no columns with unique constraints
+among them then C<find> currently will fall back to search by all other columns.  
+Don't depend on that functionality - as it can change in the future.  To not fallback
+set the 'dont_fallback' attribute to 1;
+
 If your table does not have a primary key, you B<must> provide a value for the
 C<key> attribute matching one of the unique constraints on the source.
 
@@ -381,10 +386,24 @@
   # but allow the input query in case the ResultSet defines the query or the
   # user is abusing find
   my $alias = exists $attrs->{alias} ? $attrs->{alias} : $self->{attrs}{alias};
-  my $query = @unique_queries
-    ? [ map { $self->_add_alias($_, $alias) } @unique_queries ]
-    : $self->_add_alias($input_query, $alias);
-
+  my $query;
+  if ( ! @unique_queries ){
+    if ( delete $attrs->{dont_fallback} ) {
+      if( $self->_has_uniq_cond ){
+        $query = {};
+      }
+      else {
+        return undef;
+      }
+    }
+    else{
+      carp "No unique fields found in query. Falling back to search by all query fields. This usage is deprecated. For not falling back use 'dont_fallback' attribute";
+      $query = $self->_add_alias($input_query, $alias);
+    }
+  }
+  else{
+    $query = [ map { $self->_add_alias($_, $alias) } @unique_queries ];
+  }
   # Run the query
   if (keys %$attrs) {
     my $rs = $self->search($query, $attrs);
@@ -397,6 +416,21 @@
   }
 }
 
+# _has_uniq_cond
+#
+# Check if the resultset condition identifies one row
+
+sub _has_uniq_cond {
+  my ( $self ) = @_;
+  my @condition_keys = keys %{ $self->{cond} };
+  my $source = $self->result_source;
+  for my $key ( $source->primary_columns ){
+    return 0 if not grep { $key } @condition_keys;
+  }
+  return 1;
+}
+
+
 # _add_alias
 #
 # Add the specified alias to the specified query hash. A copy is made so the
_______________________________________________
List: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/dbix-class
IRC: irc.perl.org#dbix-class
SVN: http://dev.catalyst.perl.org/repos/bast/DBIx-Class/
Searchable Archive: http://www.grokbase.com/group/[EMAIL PROTECTED]

Reply via email to