@@ -447,11 +447,7 @@ def _find_fields(self, service, value):
447
447
The `id` field used to match the resolved record is hardcoded,
448
448
as in the `read_many` method.
449
449
"""
450
- fields = []
451
- for field in self ._fields :
452
- if field .has (service , value ):
453
- fields .append (field )
454
- return fields
450
+ return [field for field in self ._fields if field .has (service , value )]
455
451
456
452
def _fetch_referenced (self , grouped_values , identity ):
457
453
"""Search and fetch referenced recs by ids."""
@@ -472,11 +468,10 @@ def _add_dereferenced_record(service, value, resolved_rec):
472
468
_add_dereferenced_record (service , value , hit )
473
469
474
470
ghost_values = all_values - found_values
475
- if ghost_values :
476
- for value in ghost_values :
477
- # set dereferenced record to None. That will trigger eventually
478
- # the field.ghost_record() to be called
479
- _add_dereferenced_record (service , value , None )
471
+ for value in ghost_values :
472
+ # set dereferenced record to None. That will trigger eventually
473
+ # the field.ghost_record() to be called
474
+ _add_dereferenced_record (service , value , None )
480
475
481
476
def resolve (self , identity , hits ):
482
477
"""Collect field values and resolve referenced records."""
@@ -510,3 +505,76 @@ def expand(self, identity, hit):
510
505
dict_merge (results , d )
511
506
512
507
return results
508
+
509
+ class MultiFieldsResolver (FieldsResolver ):
510
+ """Resolve the reference record for each of the configured fields.
511
+
512
+ Given a list of fields referencing other records/objects,
513
+ it fetches and returns the dereferenced record/obj.
514
+
515
+ This class supports resolution of nested fields and efficiently batches
516
+ resolution requests to services.
517
+ """
518
+
519
+ def _collect_values (self , hits ):
520
+ """Collect all field values to be expanded."""
521
+ grouped_values = dict ()
522
+
523
+ for hit in hits :
524
+ for field in self ._fields :
525
+ try :
526
+ value = dict_lookup (hit , field .field_name )
527
+ if value is None :
528
+ continue
529
+ except KeyError :
530
+ continue
531
+
532
+ # Ensure `get_value_service` can return multiple (v, service) tuples
533
+ values_services = field .get_value_service (value )
534
+
535
+ if not isinstance (values_services , list ):
536
+ values_services = [values_services ] # Ensure list format
537
+
538
+ for v , service in values_services :
539
+ field .add_service_value (service , v )
540
+ grouped_values .setdefault (service , set ()).add (v )
541
+
542
+ return grouped_values
543
+
544
+ def expand (self , identity , hit ):
545
+ """Expand and return the resolved fields for the given hit."""
546
+ results = {}
547
+
548
+ for field in self ._fields :
549
+ try :
550
+ value = dict_lookup (hit , field .field_name )
551
+ if value is None :
552
+ continue
553
+ except KeyError :
554
+ continue
555
+
556
+ # Ensure `get_value_service` supports lists of (value, service)
557
+ values_services = field .get_value_service (value )
558
+ resolved_recs = {}
559
+ if isinstance (values_services , list ):
560
+ resolved_recs = []
561
+ for v , service in values_services :
562
+ resolved_rec = field .get_dereferenced_record (service , v )
563
+ if resolved_rec :
564
+ resolved = field .pick (identity , resolved_rec )
565
+ if isinstance (resolved , list ):
566
+ resolved_recs .extend (resolved )
567
+ else :
568
+ resolved_recs .append (field .pick (identity , resolved_rec ))
569
+ else :
570
+ v , service = values_services
571
+ resolved_rec = field .get_dereferenced_record (service , v )
572
+ if resolved_rec :
573
+ resolved_recs = field .pick (identity , resolved_rec )
574
+ if resolved_recs :
575
+ # Maintain nested structure
576
+ d = dict ()
577
+ dict_set (d , field .field_name , resolved_recs )
578
+ dict_merge (results , d )
579
+
580
+ return results
0 commit comments