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]