def read_db_entity_trees_of_cls_to_merge( session: Session, state_code: str, schema_cls: Type[StateBase]) -> List[List[EntityTree]]: """ Returns a list of lists of EntityTree where each inner list is a group of EntityTrees with entities of class |schema_cls| that need to be merged because their entities have the same external_id. Will assert if schema_cls does not have a person_id or external_id field. """ if not StateCode.is_valid(state_code): raise ValueError(f"Invalid state code: [{state_code}]") external_ids = dao.read_external_ids_of_cls_with_external_id_match( session, state_code, schema_cls) people = dao.read_people_by_cls_external_ids(session, state_code, schema_cls, external_ids) all_cls_trees = get_all_entity_trees_of_cls(people, schema_cls) external_ids_map: Dict[str, List[EntityTree]] = defaultdict(list) for tree in all_cls_trees: if not isinstance(tree.entity, schema_cls): raise ValueError(f"Unexpected entity type [{type(tree.entity)}]") if tree.entity.external_id in external_ids: external_ids_map[tree.entity.external_id].append(tree) return [tree_list for _, tree_list in external_ids_map.items()]
def _move_events_onto_supervision_periods_for_person( matched_persons: List[schema.StatePerson], event_cls: Type[DatabaseEntity], event_field_name: str, state_code: str, ) -> None: """For each person in |matched_persons|, moves all events of type |event_cls| onto the |event_field_name| field of a matching supervision period, based on date. If there is no matching supervision period, ensures that the events hang off of a placeholder chain. """ if not StateCode.is_valid(state_code): raise ValueError(f"Invalid state code: [{state_code}]") for person in matched_persons: unmatched_events = _move_events_onto_supervision_periods( person, event_cls, event_field_name ) if not unmatched_events: continue # We may hit this case if an entity that has already been committed to the DB has a date updated in a # later run such that the dates of the existing supervision periods no longer line up with one of the # existing events. In this case, we want to store the event on a placeholder chain starting at sentence_group. # We do this to show that the supervision violation isn't associated with anything other than the person. placeholder_sg = get_or_create_placeholder_child( person, "sentence_groups", schema.StateSentenceGroup, state_code=state_code, status=StateSentenceStatus.PRESENT_WITHOUT_INFO.value, ) placeholder_s = get_or_create_placeholder_child( placeholder_sg, "supervision_sentences", schema.StateSupervisionSentence, person=person, state_code=state_code, status=StateSentenceStatus.PRESENT_WITHOUT_INFO.value, ) placeholder_sp = get_or_create_placeholder_child( placeholder_s, "supervision_periods", schema.StateSupervisionPeriod, person=person, state_code=state_code, status=StateSupervisionPeriodStatus.PRESENT_WITHOUT_INFO.value, ) placeholder_sp.set_field_from_list(event_field_name, unmatched_events)