From 37c6c40afb69fc65bd099060fefde675c7d42f17 Mon Sep 17 00:00:00 2001 From: Lebbeous Fogle-Weekley Date: Wed, 21 Mar 2012 11:32:12 -0400 Subject: [PATCH] near the finish line! just need to write process_result() two pcrud/cstore bugs need to be dealt with though, as they are easily exposed by flattener: http://pastie.org/3642150 Signed-off-by: Lebbeous Fogle-Weekley --- .../perlmods/lib/OpenILS/Application/Fielder.pm | 44 +++++++------ .../perlmods/lib/OpenILS/Application/Flattener.pm | 77 ++++++++++++++++++++-- 2 files changed, 93 insertions(+), 28 deletions(-) diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Fielder.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Fielder.pm index 486ad78125..bab2f960c5 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Fielder.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Fielder.pm @@ -158,38 +158,40 @@ sub generate_methods { sub flattened_search { my ($self, $conn, $auth, $hint, $map, $where, $slo) = @_; + # All but the last argument really are necessary. + $slo ||= {}; + # Process the map to normalize it, and to get all our joins and fleshing # structure into the jffolo. - my ($map, $jffolo) = + my ($map, $jffolo) = OpenILS::Application::Flattener::process_map($hint, $map); # Process the suppied where clause, using our map, to make the # filter. my $filter = OpenILS::Application::Flattener::prepare_filter($map, $where); - return [$filter, $jffolo]; -# # Process the supplied sort/limit/offset clause and use it to finish the -# # jffolo. -# $jffolo = OpenILS::Application::Flattener::finish_jffolo( -# $map, $jffolo, $slo -# ); + # Process the supplied sort/limit/offset clause and use it to finish the + # jffolo. + $jffolo = OpenILS::Application::Flattener::finish_jffolo( + $hint, $map, $jffolo, $slo + ); # Reach out and touch pcrud (could be cstore, if we wanted to offer # this as a private service). -# my $pcrud = create OpenSRF::AppSession("open-ils.pcrud"); -# my $req = $pcrud->request( -# "open-ils.pcrud.search.$hint", $auth, $filter, $jffolo -# ); -# -# # Stream back flattened results. -# while (my $resp = $req->recv(timeout => 60)) { -# $conn->respond( -# OpenILS::Application::Flattener::process_result($map, $resp) -# ); -# } -# -# # Clean up. -# $pcrud->kill_me; + my $pcrud = create OpenSRF::AppSession("open-ils.pcrud"); + my $req = $pcrud->request( + "open-ils.pcrud.search.$hint", $auth, $filter, $jffolo + ); + + # Stream back flattened results. + while (my $resp = $req->recv(timeout => 60)) { + $conn->respond( + OpenILS::Application::Flattener::process_result($map, $resp) + ); + } + + # Clean up. + $pcrud->kill_me; return; } diff --git a/Open-ILS/src/perlmods/lib/OpenILS/Application/Flattener.pm b/Open-ILS/src/perlmods/lib/OpenILS/Application/Flattener.pm index 4da71d170e..b5bce11d77 100644 --- a/Open-ILS/src/perlmods/lib/OpenILS/Application/Flattener.pm +++ b/Open-ILS/src/perlmods/lib/OpenILS/Application/Flattener.pm @@ -90,13 +90,13 @@ sub _flattened_search_single_join_clause { $alias = "__${column_name}_${hint}"; my $new_join; - if ($reltype eq 'has_a') { + if ($reltype eq "has_a") { $new_join = { class => $hint, fkey => $piece, field => $field }; - } elsif ($reltype eq 'has_many' or $reltype eq 'might_have') { + } elsif ($reltype eq "has_many" or $reltype eq "might_have") { $new_join = { class => $hint, fkey => $last_ident, @@ -163,9 +163,9 @@ sub _flattened_search_merge_flesh_wad { # and make it use Set::Scalar so it's more semantic, which would # mean a new Evergreen dependency. # - # The nonobvious point of the block is to merge the arrays at - # $old->{flesh_fields}{$key} and $new->{flesh_fields}{$key}, - # treating the arrays as sets. + # The nonobvious point of the following code is to merge the + # arrays at $old->{flesh_fields}{$key} and + # $new->{flesh_fields}{$key}, treating the arrays as sets. my %hash = map { $_ => 1 } ( @{ $old->{flesh_fields}{$key} }, @@ -192,6 +192,7 @@ sub _flattened_search_expand_filter_column { my $column = $map->{$key}{path}[-1]; if ($table) { + $table = "+" . $table; $o->{$table} ||= {}; $o->{$table}{$column} = $o->{$key}; @@ -213,8 +214,14 @@ sub _flattened_search_recursively_apply_map_to_filter { $state ||= {}; - if (ref $o eq 'HASH') { + if (ref $o eq "HASH") { foreach my $key (keys %$o) { + # XXX this business about "in_expr" may prove inadequate, but it's + # intended to avoid trying to map things like "between" in + # constructs like: + # {"somecolumn": {"between": [1,10]}} + # and to that extend, it succeeds. + if (not $state->{in_expr} and $key =~ /^[a-z]/) { $state->{in_expr} = 1; @@ -233,7 +240,7 @@ sub _flattened_search_recursively_apply_map_to_filter { ); } } - } elsif (ref $o eq 'ARRAY') { + } elsif (ref $o eq "ARRAY") { _flattened_search_recursively_apply_map_to_filter( $_, $map, $state ) foreach @$o; @@ -287,4 +294,60 @@ sub prepare_filter { return $filter; } +# Return a jffolo with sort/limit/offset from the simplified sort hash (slo) +# mixed in. limit and offset are copied as-is. sort is translated into +# an order_by that calls simplified column named by their real names by checking +# the map. +sub finish_jffolo { + my ($core_hint, $map, $jffolo, $slo) = @_; + + $jffolo = { %$jffolo }; # clone + $slo = { %$slo }; # clone + + $jffolo->{limit} = $slo->{limit} if exists $slo->{limit}; + $jffolo->{offset} = $slo->{offset} if exists $slo->{offset}; + + return $jffolo unless $slo->{sort}; + + # The slo has a special format for 'sort' that gives callers what they + # need, but isn't as flexible as json_query's order_by. + # + # "sort": [{"column1": "asc"}, {"column2": "desc"}] + # or optionally, + # "sort": {"onlycolumn": "asc"} + + $jffolo->{order_by} = []; + + # coerce from optional simpler format (see comment blob above) + $slo->{sort} = [ $slo->{sort} ] if ref $slo->{sort} eq "HASH"; + + foreach my $exp (@{ $slo->{sort} }) { + # XXX By assuming that each sort expression is a single key/value pair, + # we preclude the ability to use transforms and the like for now. + + my ($key) = keys(%$exp); + + if ($map->{$key}) { + my $class = $map->{$key}{last_join_alias} || $core_hint; + push @{ $jffolo->{order_by} }, { + class => $class, + field => $map->{$key}{path}[-1], + direction => $exp->{$key} + }; + } + + # If the key wasn't defined in the map, we'll leave it out of our + # order_by clause. + } + + return $jffolo; +} + +sub process_result { + my ($map, $resp) = @_; + + # XXX TODO + return $resp; +} + 1; -- 2.11.0