method => "scoped_holding_summary_tree_for_bib",
api_name => "open-ils.serial.holding_summary_tree.by_bib",
api_level => 1,
- argc => 1,
+ argc => 6,
signature => {
desc => q/Return a set of holding summaries organized into a tree
of nodes that look like:
{org_unit:<id>, holding_summaries:[], children:[]}
+
+ All arguments except the first (bibid) are optional.
/,
params => [
{ name => "bibid",
# This is a helper for grouped_holdings_for_summary() later.
sub _label_holding_level {
- my ($pattern_code, $subfield, $value) = @_;
+ my ($pattern_field, $subfield, $value) = @_;
return $value; # XXX TODO
}
# This is a helper for grouped_holdings_for_summary() later.
sub _get_deepest_holding_level {
- my ($display_grouping, $pattern_code) = @_;
-
- my $field = new MARC::Field(
- "999", @{ OpenSRF::Utils::JSON->JSON2perl($pattern_code) }
- );
-
- my @subfields = @{ $MFHD_SUMMARIZED_SUBFIELDS{$display_grouping} };
+ my ($display_grouping, $pattern_field) = @_;
- my @present = grep { $field->subfield($_) } @subfields;
+ my @present = grep { $pattern_field->subfield($_) } @{
+ $MFHD_SUMMARIZED_SUBFIELDS{$display_grouping}
+ };
return pop @present;
}
+# This is a helper for grouped_holdings_for_summary() later.
+sub _make_grouped_holding_node {
+ my ($row, $subfield, $deepest_level, $pattern_field) = @_;
+
+ return {
+ $subfield eq $deepest_level ? (
+ label => $row->{label},
+ holding => $row->{id}
+ ) : (
+ value => $row->{value},
+ label => _label_holding_level(
+ $pattern_field, $subfield, $row->{value}
+ )
+ )
+ };
+}
+
sub grouped_holdings_for_summary {
my (
$self, $client, $summary_type, $summary_id,
if (ref $_ ne 'ARRAY') {
return new OpenILS::Event(
"BAD_PARAMS", note =>
- "expand_path, limits and offsets arguments must be arrays"
+ "'expand_path', 'limits' and 'offsets' arguments must " .
+ "be arrays"
);
}
}
- if (not (scalar(@$limits) == scalar(@$expand_path) + 1) and
- (scalar(@$offsets) == scalar(@$expand_path) + 1)) {
+ if (scalar(@$limits) != scalar(@$expand_path) + 1 or
+ scalar(@$offsets) != scalar(@$expand_path) + 1) {
return new OpenILS::Event(
"BAD_PARAMS", note =>
- "limits and offsets must be one element longer than expand_path"
+ "'limits' and 'offsets' arrays each must be one element " .
+ "longer than 'expand_path'"
);
}
my $e = new_editor;
- # First, get display grouping for requested summary (either chron or enum).
+ # First, get display grouping for requested summary (either chron or enum)
+ # and the pattern code. Even though we have to JOIN through sitem to get
+ # pattern_code from scap, we don't actually care about specific items yet.
my $row = $e->json_query({
- select => {sdist => ["display_grouping"]},
- from => {$summary_hint => {sdist => {}}},
- where => {"+$summary_hint" => {id => $summary_id}}
+ select => {sdist => ["display_grouping"], scap => ["pattern_code"]},
+ from => {
+ $summary_hint => {
+ sdist => {
+ join => {
+ sstr => {
+ join => {
+ sitem => {
+ join => {
+ siss => {
+ join => {scap => {}}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ where => {
+ "+$summary_hint" => {id => $summary_id},
+ "+sitem" => {date_received => {"!=" => undef}}
+ },
+ limit => 1
}) or return $e->die_event;
- return new OpenILS::Event("BAD_PARAMS", note => "summary_id not found")
- unless @$row;
+ # Summaries without attached holdings constitute bad data, not benign
+ # empty result sets.
+ return new OpenILS::Event(
+ "BAD_PARAMS",
+ note => "Summary #$summary_id not found, or no holdings attached"
+ ) unless @$row;
- # And now we know which subfields we care about from
+ # Unless data has been disarranged, all holdings grouped together under
+ # the same summary should have the same pattern code, so we can take any
+ # result from the set we just got.
+ my $pattern_field;
+ eval {
+ $pattern_field = new MARC::Field(
+ "999", # irrelevant for our purposes
+ @{ OpenSRF::Utils::JSON->JSON2perl($row->[0]->{pattern_code}) }
+ );
+ };
+ if ($@) {
+ return new OpenILS::Event("SERIAL_CORRUPT_PATTERN_CODE", note => $@);
+ }
+
+ # And now we know which subfields we will care about from
# serial.materialized_holding_code.
my $display_grouping = $row->[0]->{display_grouping};
+
+ # This will tell us when to stop grouping and start showing actual
+ # holdings.
+ my $deepest_level =
+ _get_deepest_holding_level($display_grouping, $pattern_field);
+ if (not defined $deepest_level) {
+ # corrupt pattern code
+ my $msg = "couldn't determine deepest holding level for " .
+ "$summary_type summary #$summary_id";
+ $logger->warn($msg);
+ return new OpenILS::Event("SERIAL_CORRUPT_PATTERN_CODE", note => $msg);
+ }
+
my @subfields = @{ $MFHD_SUMMARIZED_SUBFIELDS{$display_grouping} };
# We look for holdings grouped at the top level once no matter what,
# Now get the top level of holdings.
my $top = $e->json_query({
select => {
- "smhc_$subfield" => ["value"],
- scap => ["pattern_code"]
+ "smhc_$subfield" => ["value"], (
+ $subfield eq $deepest_level ?
+ (siss => [qw/id label date_published/]) : ()
+ )
},
from => {
$summary_hint => {
sitem => {
join => {
siss => {
- join => {
- scap => {}, %subfield_joins
- }
+ join => {%subfield_joins}
}
}
}
distinct => 1, # sic, this goes here in json_query
limit => int(shift(@$limits)),
offset => int(shift(@$offsets)),
- order_by => [
- {class => "smhc_$subfield", field => "value",
- direction => "descending"}
- ]
+ order_by => {
+ "smhc_$subfield" => {
+ "value" => {
+ direction => ($subfield eq $deepest_level ? "asc" : "desc")
+ }
+ }
+ }
}) or return $e->die_event;
- # Unless data has been disarranged, all holdings grouped together under
- # the same summary should have the same pattern code, so we can take any
- # result from the set we just got.
-
- my $pattern_code = $top->[0]->{pattern_code};
-
# Make the tree we have so far.
- my $tree = [
- map {
- +{
- value => $_->{value},
- label =>
- _label_holding_level($pattern_code, $subfield, $_->{value})
- };
- } @$top
- ];
+ my $tree = [ map(
+ _make_grouped_holding_node($_,$subfield,$deepest_level,$pattern_field),
+ @$top
+ ) ];
# Ok, that got us the top level, with nothing expanded. Now we loop through
- # the deeper levels of @$expand_path, issuing similar queries to get us
- # lower groupings and even actual specific holdings.
-
- # This will tell us when to stop grouping and start showing actual
- # holdings.
- my $deepest_level =
- _get_deepest_holding_level($display_grouping, $pattern_code);
- if (not defined $deepest_level) {
- # corrupt pattern code
- my $msg = "couldn't determine deepest holding level for " .
- "$summary_type summary #$summary_id";
- $logger->warn($msg);
- return new OpenILS::Event("SERIAL_CORRUPT_PATTERN_CODE", note => $msg);
- }
-
- $logger->debug(
- "deepest holding level for $summary_type summary " .
- "#$summary_id is $deepest_level"
- );
-
+ # the elements of @$expand_path, issuing similar queries to get us deeper
+ # groupings and even actual specific holdings.
my $parent = $tree;
foreach my $value (@$expand_path) {
distinct => 1, # sic, this goes here in json_query
limit => int(shift(@$limits)),
offset => int(shift(@$offsets)),
- order_by => [
- {class => "smhc_$subfield", field => "value",
- direction => "descending"}
- ]
+ order_by => {
+ "smhc_$subfield" => {
+ "value" => {
+ direction => ($subfield eq $deepest_level?"asc":"desc")
+ }
+ }
+ }
}) or return $e->die_event;
return $tree unless @$level;
# Find attachment point for our results.
my ($point) = grep { $_->{value} eq $value } @$parent;
- # Set parent for the next iteration
+ # Set parent for the next iteration.
$parent = $point->{children} = [
- map {
- +{
- # XXX if on deepest level, show actual holdings
- value => $_->{value},
- label => _label_holding_level(
- $pattern_code, $subfield, $_->{value}
- )
- };
- } @$level
+ map(
+ _make_grouped_holding_node(
+ $_, $subfield, $deepest_level, $pattern_field
+ ),
+ @$level
+ )
];
last if $subfield eq $deepest_level;
method => "grouped_holdings_for_summary",
api_name => "open-ils.serial.holdings.grouped_by_summary",
api_level => 1,
- argc => 1,
+ argc => 5,
signature => {
desc => q/Return a tree of holdings associated with a given summary
grouped by all but the last of either chron or enum units./,