From d60597c38edc06bf1254f6955a1ec70e3d7b0afc Mon Sep 17 00:00:00 2001 From: Tomas Cohen Arazi Date: Tue, 10 Mar 2020 15:56:29 -0300 Subject: [PATCH] Bug 20212: Allow filtering orders on biblioitems fields This patch adapts the code from the list() sub so it manipulates the query parameters and the embed header so: - the biblioitem relationship is prefetch - any queries on biblio.isbn and biblio.ean are correctly translated into search on the biblioitems table. --- Koha/REST/V1/Acquisitions/Orders.pm | 145 +++++++++++++++++++++++++++- 1 file changed, 143 insertions(+), 2 deletions(-) diff --git a/Koha/REST/V1/Acquisitions/Orders.pm b/Koha/REST/V1/Acquisitions/Orders.pm index 989cb6b2e6..b6488552d7 100644 --- a/Koha/REST/V1/Acquisitions/Orders.pm +++ b/Koha/REST/V1/Acquisitions/Orders.pm @@ -22,6 +22,8 @@ use Mojo::Base 'Mojolicious::Controller'; use Koha::Acquisition::Orders; use Koha::DateUtils; +use Clone 'clone'; +use JSON qw(decode_json); use Scalar::Util qw( blessed ); use Try::Tiny; @@ -44,11 +46,102 @@ sub list { my $c = shift->openapi->valid_input or return; return try { - my $orders = $c->objects->search( Koha::Acquisition::Orders->new ); + my $orders_rs = Koha::Acquisition::Orders->new; + my $args = $c->validation->output; + my $attributes = {}; + + # Extract reserved params + my ( $filtered_params, $reserved_params, $path_params ) = $c->extract_reserved_params($args); + # Look for embeds + my $embed = $c->stash('koha.embed'); + my $fixed_embed = clone($embed); + if ( exists $fixed_embed->{biblio} ) { + # Add biblioitems to prefetch + # FIXME remove if we merge biblio + biblioitems + $fixed_embed->{biblio}->{children}->{biblioitem} = {}; + $c->stash('koha.embed', $fixed_embed); + } + + # Merge sorting into query attributes + $c->dbic_merge_sorting( + { + attributes => $attributes, + params => $reserved_params, + result_set => $orders_rs + } + ); + + # Merge pagination into query attributes + $c->dbic_merge_pagination( + { + filter => $attributes, + params => $reserved_params + } + ); + + # Generate prefetches for embedded stuff + $c->dbic_merge_prefetch( + { + attributes => $attributes, + result_set => $orders_rs + } + ); + + # Call the to_model function by reference, if defined + if ( defined $filtered_params ) { + + # Apply the mapping function to the passed params + $filtered_params = $orders_rs->attributes_from_api($filtered_params); + $filtered_params = $c->build_query_params( $filtered_params, $reserved_params ); + } + + if ( defined $path_params ) { + + # Apply the mapping function to the passed params + $filtered_params //= {}; + $path_params = $orders_rs->attributes_from_api($path_params); + foreach my $param (keys %{$path_params}) { + $filtered_params->{$param} = $path_params->{$param}; + } + } + + if ( defined $reserved_params->{q} || defined $reserved_params->{query} || defined $reserved_params->{'x-koha-query'}) { + $filtered_params //={}; + my @query_params_array; + my $query_params; + if ( exists $reserved_params->{query} and defined $reserved_params->{query} ) { + push @query_params_array, fix_query({ query => $reserved_params->{query} }); + } + if ( exists $reserved_params->{q} and defined $reserved_params->{q}) { + push @query_params_array, fix_query({ query => decode_json($reserved_params->{q}) }); + } + if ( exists $reserved_params->{'x-koha-query'} and defined $reserved_params->{'x-koha-query'} ) { + push @query_params_array, fix_query({ query => decode_json($reserved_params->{'x-koha-query'}) });; + } + + if(scalar(@query_params_array) > 1) { + $query_params = {'-and' => \@query_params_array}; + } + else { + $query_params = $query_params_array[0]; + } + + $filtered_params = $c->merge_q_params( $filtered_params, $query_params, $orders_rs ); + } + + # Perform search + my $orders = $orders_rs->search( $filtered_params, $attributes ); + + if ($orders->is_paged) { + $c->add_pagination_headers({ + total => $orders->pager->total_entries, + params => $args, + }); + } return $c->render( status => 200, - openapi => $orders + openapi => $orders->to_api({ embed => $embed }) ); } catch { @@ -226,4 +319,52 @@ sub delete { }; } +=head2 Internal methods + +=head3 fix_query + + my $query = fix_query($query); + +This method takes care of recursively fixing queries that should be done +against biblioitems (instead if biblio as exposed on the API) + +=cut + +sub fix_query { + my ($args) = @_; + + my $query = $args->{query}; + my $biblioitem_fields = { + 'biblio.isbn' => 'biblio.biblioitem.isbn', + 'biblio.ean' => 'biblio.biblioitem.ean' + }; + + if ( ref($query) eq 'HASH' ) { + foreach my $key (keys %{$query}) { + if ( exists $biblioitem_fields->{$key}) { + my $subq = delete $query->{$key}; + $query->{$biblioitem_fields->{$key}} = (ref($subq) eq 'HASH') + ? fix_query({ query => $subq }) + : $subq; + } + else { + $query->{$key} = fix_query({ query => $query->{$key} }); + } + } + } + elsif ( ref($query) eq 'ARRAY' ) { + my @accum; + foreach my $item (@{$query}) { + push @accum, fix_query({ query => $item }); + } + $query = \@accum; + } + else { # scalar + $query = $biblioitem_fields->{$query} + if exists $biblioitem_fields->{$query}; + } + + return $query; +} + 1; -- 2.26.2