source: server/trunk/web/lib/Sophie/Controller/Search.pm @ 44

Last change on this file since 44 was 44, checked in by nanardon, 14 years ago
  • improve fuzzy search
File size: 7.3 KB
Line 
1package Sophie::Controller::Search;
2use Moose;
3use namespace::autoclean;
4use Sophie;
5
6BEGIN {extends 'Catalyst::Controller'; }
7
8=head1 NAME
9
10Sophie::Controller::Search - Catalyst Controller
11
12=head1 DESCRIPTION
13
14Catalyst Controller.
15
16=head1 METHODS
17
18=cut
19
20
21=head2 index
22
23=cut
24
25sub index :Path :Args(0) {
26    my ( $self, $c ) = @_;
27
28    if ($c->req->param('page')) {
29        $c->req->params->{search} = $c->session->{search};
30    }
31
32    if ($c->req->param('search')) {
33        $c->session->{search} = $c->req->param('search');
34        $c->forward('fuzzy', [ undef, $c->req->param('search') ]);
35        my $pager = $c->stash->{rs}->pager;
36        $c->stash->{pager} = $pager;
37        $c->stash->{xmlrpc} = [
38            $c->stash->{rs}->get_column('pkgid')->all
39        ];
40    }
41}
42
43sub search_param : Private {
44    my ($self, $c) = @_;
45    my $r = {
46        rows => Sophie->config()->{'max_reply'} || 20000,
47        order_by => [ 'name', 'evr using >>', 'issrc' ],
48        select => [ 'pkgid' ],
49    };
50    if (!$c->req->xmlrpc->method) {
51        $r->{page} = $c->req->param('page') || 1;
52        $r->{rows} = 25;
53    }
54    return $r;
55}
56
57sub distrib_search : Private {
58    my ( $self, $c, $searchspec ) = @_;
59
60    return $c->model('Base')->resultset('Distribution')
61        ->search(
62            {
63                $searchspec->{distribution}
64                    ? (name => $searchspec->{distribution})
65                    : ()
66            }
67        )->search_related('Release',
68            {
69                $searchspec->{release}
70                    ? (version => $searchspec->{release})
71                    : ()
72            }
73        )->search_related('Arch',
74            {
75                $searchspec->{arch}
76                    ? (arch => $searchspec->{arch})
77                    : ()
78            }
79        )->search_related('Medias')
80        ->search_related('MediasPaths')
81        ->search_related('Paths')
82        ->search_related('Rpmfiles');
83}
84
85sub bytag : XMLRPCPath('/search/rpm/bytag') {
86    my ( $self, $c, $searchspec, $tag, $tagvalue ) = @_;
87
88    my $tagrs = $c->model('Base')->resultset('Tags')
89        ->search({ tagname => lc($tag), value => $tagvalue})
90        ->get_column('pkgid');
91    $c->stash->{xmlrpc} = [ $c->model('Base')->resultset('Rpms')->search(
92        {
93            -and => [ 
94                (exists($searchspec->{src})
95                    ? { issrc => $searchspec->{src} ? 1 : 0 }
96                    : ()),
97                { pkgid => 
98                    { IN => $tagrs->as_query, },
99                },
100                { pkgid =>
101                    { IN => $c->forward('distrib_search', [ $searchspec
102                        ])->get_column('pkgid')->as_query, }, 
103                },
104            ]     
105        },
106        $c->forward('search_param'),
107    )->get_column('pkgid')->all ]
108
109}
110
111sub bydep : XMLRPCPath('/search/rpm/bydep') {
112    my ( $self, $c, $searchspec, $deptype, $depname, $depsense, $depevr ) = @_;
113
114    my $deprs = $c->model('Base')->resultset('Deps')->search(
115        {
116            deptype => $deptype,
117            depname => $depname,
118            ($depsense
119                ? (-nest => \[
120                    'rpmdepmatch(flags, evr, rpmsenseflag(?), ?)',
121                    [ plain_text => $depsense],
122                    [ plain_text => $depevr ]
123                ])
124            : ()),
125        }
126    )->get_column('pkgid');
127    $c->stash->{xmlrpc} = [ $c->model('Base')->resultset('Rpms')->search(
128        {
129            -and => [ 
130                (exists($searchspec->{src})
131                    ? { issrc => $searchspec->{src} ? 1 : 0 }
132                    : ()),
133                { pkgid => 
134                    { IN => $deprs->as_query, },
135                },
136                { pkgid =>
137                    { IN => $c->forward('distrib_search', [ $searchspec
138                        ])->get_column('pkgid')->as_query, }, 
139                },
140            ]     
141        },
142        $c->forward('search_param'),
143    )->get_column('pkgid')->all ]
144}
145
146sub byfile : XMLRPCPath('/search/rpm/byfile') {
147    my ( $self, $c, $searchspec, $file) = @_;
148    my ($dirname, $basename) = $file =~ m:^(.*/)?([^/]+)$:;
149
150    my $filers = $c->model('Base')->resultset('Files')
151    ->search({
152            ($dirname
153                ? (dirname => $dirname)
154                : ()),
155            basename => $basename,
156        })
157    ->get_column('pkgid');
158    $c->stash->{xmlrpc} = [ $c->model('Base')->resultset('Rpms')->search(
159        {
160            -and => [ 
161                (exists($searchspec->{src})
162                    ? { issrc => $searchspec->{src} ? 1 : 0 }
163                    : ()),
164                { pkgid => 
165                    { IN => $filers->as_query, },
166                },
167                { pkgid =>
168                    { IN => $c->forward('distrib_search', [ $searchspec
169                        ])->get_column('pkgid')->as_query, }, 
170                },
171            ]     
172        },
173        $c->forward('search_param'),
174    )->get_column('pkgid')->all ]
175}
176
177sub fuzzy : XMLRPCPath('/search/rpm/fuzzy') {
178    my ($self, $c, $searchspec, $name) = @_;
179
180    my $deprs = $c->model('Base')->resultset('Deps')->search(
181        { deptype => 'P', depname => { '~*' => $name } }
182    )->get_column('pkgid');
183
184    $c->stash->{rs} = 
185
186        $c->model('Base')->resultset('Rpms')->search(
187        {
188            -and => [
189                (exists($searchspec->{src})
190                    ? { issrc => $searchspec->{src} ? 1 : 0 }
191                    : ()),
192                { -or => [
193                    { name => 
194                        { '~*' => $name, },
195                    },
196                    { pkgid =>
197                        { IN => $deprs->as_query, },
198                    }, ]
199                },
200                { pkgid =>
201                    { IN => $c->forward('distrib_search', [ $searchspec
202                        ])->get_column('pkgid')->as_query, }, 
203                },
204            ]     
205        },
206        $c->forward('search_param'),
207    );
208   
209    if ($c->req->xmlrpc->method) {
210        $c->stash->{xmlrpc} = [ 
211            $c->stash->{rs}->get_column('pkgid')->all
212        ];
213    }
214}
215
216sub description : XMLRPCPath('/search/rpm/description') {
217    my ($self, $c, $searchspec, @keywords) = @_;
218    my $tsquery = join(' & ', map { $_ =~ s/ /\\ /g; $_ } @keywords);
219    $c->stash->{xmlrpc} = [ map { $_->get_column('pkgid') } $c->model('Base')->resultset('Rpms')->search(
220        {
221            -nest => \[
222                    "to_tsvector('english', description) @@ to_tsquery(?)",
223                    [ plain_text => $tsquery],
224                ],
225                (exists($searchspec->{src})
226                    ? (issrc => $searchspec->{src} ? 1 : 0)
227                    : ()),
228                pkgid =>
229                    { IN => $c->forward('distrib_search', [ $searchspec
230                ])->get_column('pkgid')->as_query, }, 
231               
232         
233        },
234        {
235            %{$c->forward('search_param')},
236            select => [ 
237                "ts_rank_cd(to_tsvector('english', description),to_tsquery(?)) as rank",
238                'pkgid'
239            ],
240            bind => [ $tsquery ], 
241            order_by => [ 'rank desc', 'name', 'evr using >>', 'issrc' ],
242        },
243    )->all ]
244
245}
246
247=head1 AUTHOR
248
249Olivier Thauvin
250
251=head1 LICENSE
252
253This library is free software. You can redistribute it and/or modify
254it under the same terms as Perl itself.
255
256=cut
257
258__PACKAGE__->meta->make_immutable;
259
2601;
Note: See TracBrowser for help on using the repository browser.