Support fields object in search responses

Change-Id: I4c80d06182852fb56f77072789f04bd0f6b94f94
diff --git a/Changes b/Changes
index 8bc6ddf..7df990f 100644
--- a/Changes
+++ b/Changes
@@ -11,6 +11,7 @@
         - Add pages to references in snippet view. (diewald)
         - Added category to Piwik calls. (diewald)
         - Add SpaCy with STTS to annotation assistant. (diewald)
+        - Support field objects in search responses. (diewald)
 
 0.54 2024-06-10
         - Remove deprecated 'matchInfo' API path. (diewald, margaretha)
diff --git a/lib/Kalamar/Controller/Search.pm b/lib/Kalamar/Controller/Search.pm
index dcb13e8..5edd2ae 100644
--- a/lib/Kalamar/Controller/Search.pm
+++ b/lib/Kalamar/Controller/Search.pm
@@ -545,6 +545,10 @@
 sub _map_match {
   my $match = shift or return;
 
+  if ($match->{fields}) {
+    _flatten_fields($match->{fields}, $match);
+  };
+
   # Legacy match id
   if ($match->{matchID}) {
     $match->{matchID} =~ s/^match\-(?:[^!]+!|[^_]+_)[^\.]+?\..+?-([pc]\d)/$1/ or
@@ -564,6 +568,20 @@
 };
 
 
+# Flatten requested field objects
+sub _flatten_fields {
+  my $fields_obj = shift;
+  my $flat_fields = shift // {};
+
+  return $flat_fields if ref $fields_obj ne 'ARRAY';
+
+  foreach (@{$fields_obj}) {
+    next unless ref $_ ne 'HASH' || $_->{'key'};
+    $flat_fields->{$_->{'key'}} //= $_->{value};
+  };
+  return $flat_fields;
+};
+
 1;
 
 
diff --git a/t/query.t b/t/query.t
index 5e6869e..924cd73 100644
--- a/t/query.t
+++ b/t/query.t
@@ -2,6 +2,7 @@
 use Test::Mojo;
 use Test::More;
 use Mojo::File qw/path/;
+use Mojo::JSON qw'decode_json';
 use Kalamar::Controller::Search;
 
 
@@ -350,5 +351,34 @@
 is(defined $err ? $err->text : '', '');
 
 
+my $base_fixtures = path(Mojo::File->new(__FILE__)->dirname, 'fixtures');
+my $text_info = $base_fixtures->child('response_textinfo_goe_agi_00000.json')->slurp;
+my $fields = decode_json($text_info)->{json}->{document}->{fields};
+
+my $f = Kalamar::Controller::Search::_flatten_fields($fields);
+
+is($f->{textSigle}, 'GOE/AGI/00000');
+is($f->{author}, 'Goethe, Johann Wolfgang von');
+is($f->{docSigle}, 'GOE/AGI');
+is($f->{docTitle}, 'Goethe: Autobiographische Schriften III, (1813-1816, 1819-1829)');
+is($f->{textType}, 'Autobiographie');
+is($f->{language}, 'de');
+is($f->{availability}, 'ACA-NC');
+is($f->{title}, 'Italienische Reise');
+is($f->{creationDate}, '1813');
+is($f->{pubDate}, '1982');
+is($f->{reference}, 'Goethe, Johann Wolfgang von: Italienische Reise. Auch ich in Arkadien!, (Geschrieben: 1813-1816), In: Goethe, Johann Wolfgang von: Goethes Werke, Bd. 11, Autobiographische Schriften III, Hrsg.: Trunz, Erich. München: Verlag C. H. Beck, 1982, S. 9-349');
+is($f->{subTitle}, 'Auch ich in Arkadien!');
+is($f->{tokenSource}, 'base#tokens');
+is($f->{foundries}, 'corenlp corenlp/constituency corenlp/morpho corenlp/sentences dereko dereko/structure dereko/structure/base-sentences-paragraphs-pagebreaks malt malt/dependency marmot marmot/morpho opennlp opennlp/morpho opennlp/sentences treetagger treetagger/morpho');
+is($f->{publisher}, 'Verlag C. H. Beck');
+is($f->{corpusAuthor}, 'Goethe, Johann Wolfgang von');
+is($f->{layerInfos}, 'corenlp/c=spans corenlp/p=tokens corenlp/s=spans dereko/s=spans malt/d=rels marmot/m=tokens marmot/p=tokens opennlp/p=tokens opennlp/s=spans tt/l=tokens tt/p=tokens');
+is($f->{pubPlace}, 'München');
+is($f->{corpusTitle}, 'Goethes Werke');
+is($f->{corpusSigle}, 'GOE');
+is($f->{corpusEditor}, 'Trunz, Erich');
+
+
 done_testing;
 __END__