@@ -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,77 @@ def expand(self, identity, hit):
510
505
dict_merge (results , d )
511
506
512
507
return results
508
+
509
+
510
+ class MultiFieldsResolver (FieldsResolver ):
511
+ """Resolve the reference record for each of the configured fields.
512
+
513
+ Given a list of fields referencing other records/objects,
514
+ it fetches and returns the dereferenced record/obj.
515
+
516
+ This class supports resolution of nested fields and efficiently batches
517
+ resolution requests to services.
518
+ """
519
+
520
+ def _collect_values (self , hits ):
521
+ """Collect all field values to be expanded."""
522
+ grouped_values = dict ()
523
+
524
+ for hit in hits :
525
+ for field in self ._fields :
526
+ try :
527
+ value = dict_lookup (hit , field .field_name )
528
+ if value is None :
529
+ continue
530
+ except KeyError :
531
+ continue
532
+
533
+ # Ensure `get_value_service` can return multiple (v, service) tuples
534
+ values_services = field .get_value_service (value )
535
+
536
+ if not isinstance (values_services , list ):
537
+ values_services = [values_services ] # Ensure list format
538
+
539
+ for v , service in values_services :
540
+ field .add_service_value (service , v )
541
+ grouped_values .setdefault (service , set ()).add (v )
542
+
543
+ return grouped_values
544
+
545
+ def expand (self , identity , hit ):
546
+ """Expand and return the resolved fields for the given hit."""
547
+ results = {}
548
+
549
+ for field in self ._fields :
550
+ try :
551
+ value = dict_lookup (hit , field .field_name )
552
+ if value is None :
553
+ continue
554
+ except KeyError :
555
+ continue
556
+
557
+ # Ensure `get_value_service` supports lists of (value, service)
558
+ values_services = field .get_value_service (value )
559
+ resolved_recs = {}
560
+ if isinstance (values_services , list ):
561
+ resolved_recs = []
562
+ for v , service in values_services :
563
+ resolved_rec = field .get_dereferenced_record (service , v )
564
+ if resolved_rec :
565
+ resolved = field .pick (identity , resolved_rec )
566
+ if isinstance (resolved , list ):
567
+ resolved_recs .extend (resolved )
568
+ else :
569
+ resolved_recs .append (field .pick (identity , resolved_rec ))
570
+ else :
571
+ v , service = values_services
572
+ resolved_rec = field .get_dereferenced_record (service , v )
573
+ if resolved_rec :
574
+ resolved_recs = field .pick (identity , resolved_rec )
575
+ if resolved_recs :
576
+ # Maintain nested structure
577
+ d = dict ()
578
+ dict_set (d , field .field_name , resolved_recs )
579
+ dict_merge (results , d )
580
+
581
+ return results
0 commit comments