@@ -, +, @@ $ kshell k$ prove t/db_dependent/Koha/Object* \ t/db_dependent/Koha/REST/Plugin/Objects.t \ t/db_dependent/Koha/REST/Plugin/Query.t --- Koha/Object.pm | 24 ++++++++++++++++++ Koha/Objects.pm | 16 ++++++++++++ Koha/REST/Plugin/Objects.pm | 8 ++++++ Koha/REST/Plugin/Query.pm | 49 +++++++++++++++++++++++++++++++++++++ 4 files changed, 97 insertions(+) --- a/Koha/Object.pm +++ a/Koha/Object.pm @@ -372,6 +372,30 @@ sub _numeric_column_type { return ( grep { $column_type eq $_ } @numeric_types) ? 1 : 0; } +=head3 prefetch_whitelist + + my $whitelist = $object->prefetch_whitelist() + +Returns a hash of prefetchable subs and the type they return. + +=cut + +sub prefetch_whitelist { + my ( $self ) = @_; + + my $whitelist = {}; + my $relations = $self->_result->result_source->_relationships; + foreach my $key (keys %{$relations}) { + if($self->can($key)) { + my $result_class = $relations->{$key}->{class}; + my $obj = $result_class->new; + $whitelist->{$key} = $obj->koha_object_class if $obj->can('koha_object_class'); + } + } + + return $whitelist; +} + =head3 to_api my $object_for_api = $object->to_api( --- a/Koha/Objects.pm +++ a/Koha/Objects.pm @@ -351,6 +351,22 @@ sub from_api_mapping { return $self->{_singular_object}->from_api_mapping; } +=head3 prefetch_whitelist + + my $whitelist = $object->prefetch_whitelist() + +Returns a hash of prefetchable subs and the type it returns + +=cut + +sub prefetch_whitelist { + my ( $self ) = @_; + + $self->{_singular_object} ||= $self->object_class->new(); + + $self->{_singular_object}->prefetch_whitelist; +} + =head3 Koha::Objects->_wrap wraps the DBIC object in a corresponding Koha object --- a/Koha/REST/Plugin/Objects.pm +++ a/Koha/REST/Plugin/Objects.pm @@ -71,6 +71,14 @@ sub register { } ); + # Generate prefetches for embedded stuff + $c->dbic_merge_prefetch( + { + attributes => $attributes, + result_set => $result_set + } + ); + # Call the to_model function by reference, if defined if ( defined $filtered_params ) { --- a/Koha/REST/Plugin/Query.pm +++ a/Koha/REST/Plugin/Query.pm @@ -100,6 +100,35 @@ Generates the DBIC order_by attributes based on I<$params>, and merges into I<$a } ); +=head3 dbic_merge_prefetch + + $attributes = $c->dbic_merge_prefetch({ attributes => $attributes, result_set => $result_set }); + +Generates the DBIC prefetch attribute based on embedded relations, and merges into I<$attributes>. + +=cut + + $app->helper( + 'dbic_merge_prefetch' => sub { + my ( $c, $args ) = @_; + my $attributes = $args->{attributes}; + my $result_set = $args->{result_set}; + my $embed = $c->stash('koha.embed'); + + return unless defined $embed; + + my @prefetches; + foreach my $key (keys %{$embed}) { + my $parsed = _parse_prefetch($key, $embed, $result_set); + push @prefetches, $parsed if defined $parsed; + } + + if(scalar(@prefetches)) { + $attributes->{prefetch} = \@prefetches; + } + } + ); + =head3 _build_query_params_from_api my $params = _build_query_params_from_api( $filtered_params, $reserved_params ); @@ -287,4 +316,24 @@ sub _merge_embed { } } +sub _parse_prefetch { + my ( $key, $embed, $result_set) = @_; + + my $ko_class = $result_set->prefetch_whitelist->{$key}; + + return unless defined $ko_class; + + return $key unless defined $embed->{$key}->{children}; + + my $prefetch = {}; + foreach my $child (keys %{$embed->{$key}->{children}}) { + my $parsed = _parse_prefetch($child, $embed->{$key}->{children}, $ko_class->new); + $prefetch->{$child} = $parsed if defined $parsed; + } + + return unless scalar(keys %{$prefetch}); + + return $prefetch; +} + 1; --