def add(self, first_pid, second_pid): """Create a new relation between first and second. Use cases: * first or second have no relations of this type: simply create the relation by using the first has parent and the second as child. * first or second have already an existing relation of this type. In this case, all PIDs of any relation of first or second are removed from the db. All PIDs, including the new ones, are added to a set for new relations to create. A new parent is randomly chosen from this set and new relations are created. Example: 1 -> 2 <rel-type-1> 1 -> 3 <rel-type-1> 4 -> 5 <rel-type-1> add(3, 4) 1 -> 2 <rel-type-1> 1 -> 3 <rel-type-1> 1 -> 4 <rel-type-1> 1 -> 5 <rel-type-1> """ # get all relations where first is a parent or a child, or second is # a parent or a child (any relation where first or second are involved) all_relations = self.get_any_relation_of(first_pid, second_pid) if not all_relations: # parent or child has no relations yet PIDRelation.create(first_pid, second_pid, self.relation_type.id) else: if self.relation_exists(first_pid, second_pid): # there should be only one possible relation for this PID # for a given `relation_type` # do not raise because it might be that user is just adding # metadata to an existing relation return # parent or child has already at least one relation # compute a `set` with all PIDs pids_to_relate = set() for rel in all_relations: pids_to_relate.add(rel.parent) pids_to_relate.add(rel.child) # add to the set the first and the second (the new relation) pids_to_relate.add(first_pid) pids_to_relate.add(second_pid) self._recreate_relations_with_random_parent( all_relations, pids_to_relate )
def serialize_relations(pid): """Serialize the relations for given PID.""" data = {} relations = PIDRelation.get_child_relations(pid).all() for relation in relations: rel_cfg = resolve_relation_type_config(relation.relation_type) dump_relation(rel_cfg.api(relation.parent), rel_cfg, pid, data) parent_relations = PIDRelation.get_parent_relations(pid).all() rel_cfgs = set([resolve_relation_type_config(p) for p in parent_relations]) for rel_cfg in rel_cfgs: dump_relation(rel_cfg.api(pid), rel_cfg, pid, data) return data
def _recreate_relations_with_random_parent(self, relations_to_delete, pids_to_relate): """Delete existing relations and re-create them with a new parent.""" # elect a new parent randomly new_parent = pids_to_relate.pop() # get the remaining PIDs, future children remaining_pids = list(pids_to_relate) with db.session.begin_nested(): # delete all existing relations for rel in relations_to_delete: db.session.delete(rel) # re-create all relations with the new parent for pid in remaining_pids: PIDRelation.create(new_parent, pid, self.relation_type.id)
def serialize_relations(pid): """Serialize the relations for given PID.""" data = {} relations = PIDRelation.get_child_relations(pid).all() parent_relation = PIDRelation.get_parent_relations(pid).first() if parent_relation: relations.append(parent_relation) for relation in relations: rel_cfg = resolve_relation_type_config(relation.relation_type) schema_class = rel_cfg.schema schema = schema_class() schema.context['pid'] = pid result, errors = schema.dump(rel_cfg.api(relation=relation)) data.setdefault(rel_cfg.name, []).append(result) return data
def add(self, parent_pid, child_pid): """Add a new relation between parent and child.""" if self.relation_exists(parent_pid, child_pid): raise RecordRelationsError( "The relation `{}` between PID `{}` and PID `{}` already " "exists".format( self.relation_type.name, parent_pid.pid_value, child_pid.pid_value, )) with db.session.begin_nested(): return PIDRelation.create(parent_pid, child_pid, self.relation_type.id)
def add(self, previous_pid, next_pid): """Add a new relation between previous and next pid.""" if self.relation_exists(previous_pid, next_pid): raise RecordRelationsError( "The relation `{}` between parent PID `{}` and child PID `{}` " "already exists".format( self.relation_type.name, previous_pid.pid_value, next_pid.pid_value, )) with db.session.begin_nested(): return PIDRelation.create(previous_pid, next_pid, self.relation_type.id)