From 921914f75217f37399ba79e6fa36184f5df1f18e Mon Sep 17 00:00:00 2001 From: Don Armstrong Date: Mon, 19 May 2014 16:04:19 -0700 Subject: [PATCH] Add initial DB search support to Debbugs::Bugs --- Debbugs/Bugs.pm | 120 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 117 insertions(+), 3 deletions(-) diff --git a/Debbugs/Bugs.pm b/Debbugs/Bugs.pm index 1e8eb70..d8680d1 100644 --- a/Debbugs/Bugs.pm +++ b/Debbugs/Bugs.pm @@ -152,6 +152,8 @@ bug should not. =cut +my $_non_search_key_regex = qr/^(bugs|archive|usertags|schema)$/; + my %_get_bugs_common_options = (package => {type => SCALAR|ARRAYREF, optional => 1, @@ -198,6 +200,9 @@ my %_get_bugs_common_options = usertags => {type => HASHREF, optional => 1, }, + schema => {type => OBJECT, + optional => 1, + }, ); @@ -218,7 +223,7 @@ sub get_bugs{ return keys %bugs; } # A configuration option will set an array that we'll use here instead. - for my $routine (qw(Debbugs::Bugs::get_bugs_by_idx Debbugs::Bugs::get_bugs_flatfile)) { + for my $routine (qw(Debbugs::Bugs::get_bugs_by_db Debbugs::Bugs::get_bugs_by_idx Debbugs::Bugs::get_bugs_flatfile)) { my ($package) = $routine =~ m/^(.+)\:\:/; eval "use $package;"; if ($@) { @@ -427,11 +432,11 @@ sub get_bugs_by_idx{ delete @param{qw(maint src)}; $param{package} = [@packages]; } - my $keys = grep {$_ !~ /^(archive|usertags|bugs)$/} keys(%param); + my $keys = grep {$_ !~ $_non_search_key_regex} keys(%param); die "Need at least 1 key to search by" unless $keys; my $arc = $param{archive} ? '-arc':''; my %idx; - for my $key (grep {$_ !~ /^(archive|usertags|bugs)$/} keys %param) { + for my $key (grep {$_ !~ $_non_search_key_regex} keys %param) { my $index = $key; $index = 'submitter-email' if $key eq 'submitter'; $index = "$config{spool_dir}/by-${index}${arc}.idx"; @@ -474,6 +479,115 @@ sub get_bugs_by_idx{ } +=head2 get_bugs_by_db + +This routine uses the database to try to speed up +searches. + + +=cut + +my $_get_bugs_by_db_options = + {hash_slice(%_get_bugs_common_options, + (qw(package submitter severity tag archive), + qw(owner src maint bugs correspondent), + qw(affects usertags)) + ), + schema => {type => OBJECT, + }, + }; +sub get_bugs_by_db{ + my %param = validate_with(params => \@_, + spec => $_get_bugs_by_db_options, + ); + my %bugs = (); + + # If we're given an empty maint (unmaintained packages), we can't + # handle it, so bail out here + for my $maint (make_list(exists $param{maint}?$param{maint}:[])) { + if (defined $maint and $maint eq '') { + die "Can't handle empty maint (unmaintained packages) in get_bugs_by_idx"; + } + } + + # We handle src packages, maint and maintenc by mapping to the + # appropriate binary packages, then removing all packages which + # don't match all queries + my @packages = __handle_pkg_src_and_maint(map {exists $param{$_}?($_,$param{$_}):()} + qw(package src maint) + ); + if (exists $param{package} or + exists $param{src} or + exists $param{maint}) { + delete @param{qw(maint src)}; + $param{package} = [@packages]; + } + my $keys = grep {$_ !~ $_non_search_key_regex} keys(%param); + die "Need at least 1 key to search by" unless $keys; + my $rs = $param{schema}->resultset('Bug'); + if (exists $param{severity}) { + $rs = $rs->search([map {('severity.severity' => $_)} make_list($param{severity})], + {join => 'severity'}, + ); + } + for my $key (qw(owner submitter done)) { + if (exists $param{$key}) { + $rs = $rs->search([map {("${key}.addr" => $_)} make_list($param{$key})], + {join => $key}, + ); + } + } + if (exists $param{correspondent}) { + $rs = $rs->search([map {('message_correspondents.addr' => $_)} make_list($param{correspondent})], + {join => {correspondent => + {bug_messages => + {message => 'message_correspondents'}}}}, + ); + } + if (exists $param{affects}) { + $rs = $rs->search([map {('bin_pkg.pkg' => $_)} make_list($param{affects}), + map {('src_pkg.pkg' => $_)} make_list($param{affects}), + ], + {join => [{bug_affects_binpackages => 'bin_pkg'}, + {bug_affects_srcpackages => 'src_pkg'}, + ], + }, + ); + } + if (exists $param{package}) { + $rs = $rs->search([map {('bin_pkg.pkg' => $_)} make_list($param{package})], + {join => {bug_binpackages => 'bin_pkg'}}); + } + if (exists $param{src}) { + $rs = $rs->search([map {('src_pkg.pkg' => $_)} make_list($param{src})], + {join => {bug_srcpackages => 'src_pkg'}}); + } + # tags are very odd, because we must handle usertags. + if (exists $param{tag}) { + # bugs from usertags which matter + my %bugs_matching_usertags; + for my $bug (make_list(grep {defined $_ } @{$param{usertags}}{make_list($param{tag})})) { + $bugs_matching_usertags{$bug} = 1; + } + # we want all bugs which either match the tag name given in + # param, or have a usertag set which matches one of the tag + # names given in param. + $rs = $rs->search([map {('tag.tag' => $_)} make_list($param{tag}), + map {('me.id' => $_)} keys %bugs_matching_usertags + ], + {join => {bug_tags => 'tag'}}); + } + if (exists $param{bugs}) { + $rs = $rs->search([map {('me.id' => $_)} make_list($param{bugs})]); + } + # handle archive + if (defined $param{archive} and $param{archive} ne 'both') { + $rs = $rs->search('me.archived' => $param{archive}) + } + return $rs->get_column('id')->all(); +} + + =head2 get_bugs_flatfile This is the fallback search routine. It should be able to complete all -- 2.39.2