Skip to content

Commit

Permalink
move ES::Query role out of the web-app
Browse files Browse the repository at this point in the history
  • Loading branch information
mickeyn committed Nov 23, 2016
1 parent 57f3c8e commit f826582
Show file tree
Hide file tree
Showing 7 changed files with 158 additions and 101 deletions.
77 changes: 77 additions & 0 deletions lib/MetaCPAN/Document/Author.pm
Expand Up @@ -12,6 +12,8 @@ use MetaCPAN::Types qw(:all);
use MooseX::Types::Structured qw(Dict Tuple Optional);
use MetaCPAN::Util;

with 'MetaCPAN::Role::ES::Query';

has name => (
is => 'ro',
required => 1,
Expand Down Expand Up @@ -139,6 +141,81 @@ sub validate {
return @result;
}

sub by_id {
my ( $self, $req, $ids ) = @_;
my @ids = map {uc} ( $ids ? $ids : $req->read_param('id') );
return $self->es_by_terms_vals(
req => $req,
should => {
pauseid => \@ids,
},
);
}

sub by_id_for_top_uploaders {
my ( $self, $req, $counts ) = @_;
my $authors = $self->by_id( $req, [ keys %$counts ] );
return [
sort { $b->{releases} <=> $a->{releases} } map {
{
%{ $_->{_source} },
releases => $counts->{ $_->{_source}->{pauseid} }
}
} @{ $authors->{hits}{hits} }
];
}

sub by_user {
my ( $self, $req ) = @_;
my @users = $req->read_param('user');
return $self->es_by_terms_vals(
req => $req,
should => {
user => \@users,
},
);
}

sub by_key {
my ( $self, $req ) = @_;
my $key = $req->parameters->{key};
$key or return;

my $filter = +{
bool => {
should => [
{
match => {
'name.analyzed' =>
{ query => $key, operator => 'and' }
}
},
{
match => {
'asciiname.analyzed' =>
{ query => $key, operator => 'and' }
}
},
{ match => { 'pauseid' => uc($key) } },
{ match => { 'profile.id' => lc($key) } },
]
}
};
my $cb = sub {
my $res = shift;
return +{
results => [
map { +{ %{ $_->{_source} }, id => $_->{_id} } }
@{ $res->{hits}{hits} }
],
total => $res->{hits}{total} || 0,
took => $res->{took}
};
};

$self->es_by_filter( req => $req, filter => $filter, cb => $cb );
}

__PACKAGE__->meta->make_immutable;

1;
Expand Down
11 changes: 11 additions & 0 deletions lib/MetaCPAN/Document/Favorite.pm
Expand Up @@ -10,6 +10,8 @@ use DateTime;
use MetaCPAN::Types qw(:all);
use MetaCPAN::Util;

with 'MetaCPAN::Role::ES::Query';

has id => (
is => 'ro',
id => [qw(user distribution)],
Expand All @@ -33,5 +35,14 @@ has date => (
default => sub { DateTime->now },
);

sub by_user {
my ( $self, $req ) = @_;
my @users = $req->read_param('user');
return $self->es_by_terms_vals(
req => $req,
should => +{ user => \@users }
);
}

__PACKAGE__->meta->make_immutable;
1;
36 changes: 35 additions & 1 deletion lib/MetaCPAN/Document/Release.pm
Expand Up @@ -10,6 +10,8 @@ use DateTime;
use MetaCPAN::Types qw(:all);
use MetaCPAN::Util qw( numify_version );

with 'MetaCPAN::Role::ES::Query';

=head1 PROPERTIES
=head2 id
Expand Down Expand Up @@ -416,13 +418,45 @@ sub top_uploaders {
size => 0,
};

return $self->es->search(
my $data = $self->es->search(
{
index => $self->index->name,
type => 'release',
body => $body,
}
);

return +{
counts => +{
map { $_->{key} => $_->{doc_count} }
@{ $data->{aggregations}{author}{entries}{buckets} }
},
took => $data->{took},
total => $data->{aggregations}{author}{total},
};
}

sub by_name_and_author {
my ( $self, $req ) = @_;
my ( $name, $author ) = @{ $req->parameters }{qw< name author >};
return $self->es_by_terms_vals(
req => $req,
must => {
name => $name,
author => $author,
},
);
}

sub versions {
my ( $self, $req ) = @_;
my @dists = $req->read_parameter('distribution');
return $self->es_by_terms_vals(
req => $req,
should => {
distribution => \@dists,
},
);
}

__PACKAGE__->meta->make_immutable;
Expand Down
@@ -1,4 +1,4 @@
package MetaCPAN::Server::Role::ES::Query;
package MetaCPAN::Role::ES::Query;

use strict;
use warnings;
Expand All @@ -9,43 +9,43 @@ use Ref::Util qw( is_arrayref is_coderef );

# queries by given terms and values
sub es_by_terms_vals {
my ( $self, %args ) = @_;
my ( $c, $cb, $should, $must ) = @args{qw< c cb should must >};
die;
my ( $self, %args ) = @_;
my ( $should, $must ) = delete @args{qw< should must >};
my $filter
= $should
? _filter_bool_terms_values( should => $should )
: _filter_bool_terms_values( must => $must );
return $self->es_by_filter( c => $c, cb => $cb, filter => $filter );
return $self->es_by_filter( %args, filter => $filter );
}

# queries by given filter
sub es_by_filter {
my ( $self, %args ) = @_;
my ( $c, $cb, $filter, $_model ) = @args{qw< c cb filter model >};
my $model = $_model ? $c->model($_model) : $self->model($c);
my $res = $model->raw->filter($filter);
return $self->es_query_res( c => $c, cb => $cb, res => $res );
my $filter = delete $args{filter};
my $res = $self->raw->filter($filter);
return $self->es_query_res( %args, res => $res );
}

# applies generic 'size', 'sort' & 'fields' to
# query result
sub es_query_res {
my ( $self, %args ) = @_;
my ( $c, $cb, $res ) = @args{qw< c cb res >};
my $params = $c->req->parameters;
my ( $req, $res, $cb ) = @args{qw< req res cb >};
my $params = $req->parameters;

my $size = $params->{size} || 5000;

my @fields;
if ( $params->{fields} ) {
@fields = $c->req->read_param('fields');
@fields = $req->read_param('fields');
}

my @sort;
if ( $params->{sort} ) {
@sort
= map { /^(.*):((?:desc|asc))$/ ? { $1 => { order => $2 } } : $_ }
$c->req->read_param('sort');
$req->read_param('sort');
}

$res = $res->fields( \@fields ) if @fields;
Expand Down
76 changes: 14 additions & 62 deletions lib/MetaCPAN/Server/Controller/Author.pm
Expand Up @@ -8,7 +8,6 @@ use Moose;
BEGIN { extends 'MetaCPAN::Server::Controller' }

with 'MetaCPAN::Server::Role::JSONP';
with 'MetaCPAN::Server::Role::ES::Query';

__PACKAGE__->config(
relationships => {
Expand Down Expand Up @@ -63,84 +62,37 @@ sub get : Path('') : Args(1) {
# endpoint: /author/by_id?id=<pauseid>[&fields=<field>][&sort=<sort_key>][&size=N]
sub by_id : Path('by_id') : Args(0) {
my ( $self, $c ) = @_;
my @ids = map {uc} $c->req->read_param('id');
$c->stash(
$self->es_by_terms_vals( c => $c, should => +{ pauseid => \@ids } ) );
my $data = $self->model($c)->raw->by_id( $c->req );
$c->stash($data);
}

# endpoint: /author/by_user?user=<user_id>[&fields=<field>][&sort=<sort_key>][&size=N]
sub by_user : Path('by_user') : Args(0) {
my ( $self, $c ) = @_;
my @users = $c->req->read_param('user');
$c->stash(
$self->es_by_terms_vals( c => $c, should => +{ user => \@users } ) );
my $data = $self->model($c)->raw->by_user( $c->req );
$c->stash($data);
}

# endpoint: /author/by_key?key=<key>[&fields=<field>][&sort=<sort_key>][&size=N]
sub by_key : Path('by_key') : Args(0) {
my ( $self, $c ) = @_;
my $key = $c->req->parameters->{key};
$key or return;
my $filter = +{
bool => {
should => [
{
match => {
'name.analyzed' =>
{ query => $key, operator => 'and' }
}
},
{
match => {
'asciiname.analyzed' =>
{ query => $key, operator => 'and' }
}
},
{ match => { 'pauseid' => uc($key) } },
{ match => { 'profile.id' => lc($key) } },
]
}
};

my $cb = sub {
my $res = shift;
return +{
results => [
map { +{ %{ $_->{_source} }, id => $_->{_id} } }
@{ $res->{hits}{hits} }
],
total => $res->{hits}{total} || 0,
took => $res->{took}
};
};

$c->stash( $self->es_by_filter( c => $c, filter => $filter, cb => $cb ) );
my $data = $self->model($c)->raw->by_key( $c->req );
$data or return;
$c->stash($data);
}

# endpoint: /author/top_uploaders?range=<range>[&fields=<field>][&sort=<sort_key>][&size=N]
sub top_uploaders : Path('top_uploaders') : Args(0) {
my ( $self, $c ) = @_;
my $range = $c->req->parameters->{range};
my $data = $c->model('CPAN::Release')->top_uploaders;
my $counts = +{ map { $_->{key} => $_->{doc_count} }
@{ $data->{aggregations}{author}{entries}{buckets} } };
my $authors = $self->es_by_terms_vals(
c => $c,
should => { pauseid => [ keys %$counts ] }
);
my $range = $c->req->parameters->{range};
my $data = $c->model('CPAN::Release')->top_uploaders;
my $authors = $self->model($c)
->raw->by_id_for_top_uploaders( $c->req, delete $data->{counts} );
$c->stash(
{
authors => [
sort { $b->{releases} <=> $a->{releases} } map {
{
%{ $_->{_source} },
releases => $counts->{ $_->{_source}->{pauseid} }
}
} @{ $authors->{hits}{hits} }
],
took => $data->{took},
total => $data->{aggregations}{author}{total},
range => $range,
%$data,
authors => $authors,
range => $range,
}
);
}
Expand Down
6 changes: 2 additions & 4 deletions lib/MetaCPAN/Server/Controller/Favorite.pm
Expand Up @@ -8,7 +8,6 @@ use Moose;
BEGIN { extends 'MetaCPAN::Server::Controller' }

with 'MetaCPAN::Server::Role::JSONP';
with 'MetaCPAN::Server::Role::ES::Query';

sub find : Path('') : Args(2) {
my ( $self, $c, $user, $distribution ) = @_;
Expand All @@ -30,9 +29,8 @@ sub find : Path('') : Args(2) {
# endpoint: /favorite/by_user?user=<id>[&user=<id2>][&fields=<field>][&sort=<sort_key>][&size=N]
sub by_user : Path('by_user') : Args(0) {
my ( $self, $c ) = @_;
my @users = $c->req->read_param('user');
$c->stash(
$self->es_by_terms_vals( c => $c, should => +{ user => \@users } ) );
my $data = $self->model($c)->raw->by_user( $c->req );
$c->stash($data);
}

__PACKAGE__->meta->make_immutable;
Expand Down

0 comments on commit f826582

Please sign in to comment.