near the finish line! just need to write process_result()
authorLebbeous Fogle-Weekley <lebbeous@esilibrary.com>
Wed, 21 Mar 2012 15:32:12 +0000 (11:32 -0400)
committerLebbeous Fogle-Weekley <lebbeous@esilibrary.com>
Wed, 21 Mar 2012 16:16:05 +0000 (12:16 -0400)
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 <lebbeous@esilibrary.com>
Open-ILS/src/perlmods/lib/OpenILS/Application/Fielder.pm
Open-ILS/src/perlmods/lib/OpenILS/Application/Flattener.pm

index 486ad78..bab2f96 100644 (file)
@@ -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;
 }
index 4da71d1..b5bce11 100644 (file)
@@ -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;