Пример #1
0
class Link:
    object_: Optional[Entity]  # Needed for first/last appearance

    def __init__(self,
                 row: dict[str, Any],
                 domain: Optional[Entity] = None,
                 range_: Optional[Entity] = None) -> None:
        from openatlas.models.entity import Entity
        from openatlas.util.util import format_date_part
        self.id = row['id']
        self.description = row['description']
        self.property = g.properties[row['property_code']]
        self.domain = domain if domain else Entity.get_by_id(row['domain_id'])
        self.range = range_ if range_ else Entity.get_by_id(row['range_id'])
        self.type = g.types[row['type_id']] if row['type_id'] else None
        self.types: dict[Entity, None] = {}
        if 'type_id' in row and row['type_id']:
            self.types[g.types[row['type_id']]] = None
        if 'begin_from' in row:
            self.begin_from = timestamp_to_datetime64(row['begin_from'])
            self.begin_to = timestamp_to_datetime64(row['begin_to'])
            self.begin_comment = row['begin_comment']
            self.end_from = timestamp_to_datetime64(row['end_from'])
            self.end_to = timestamp_to_datetime64(row['end_to'])
            self.end_comment = row['end_comment']
            self.first = format_date_part(self.begin_from, 'year') \
                if self.begin_from else None
            self.last = format_date_part(self.end_from, 'year') \
                if self.end_from else None
            self.last = format_date_part(self.end_to, 'year') \
                if self.end_to else self.last

    def update(self) -> None:
        Db.update({
            'id': self.id,
            'property_code': self.property.code,
            'domain_id': self.domain.id,
            'range_id': self.range.id,
            'type_id': self.type.id if self.type else None,
            'description': self.description,
            'begin_from': datetime64_to_timestamp(self.begin_from),
            'begin_to': datetime64_to_timestamp(self.begin_to),
            'begin_comment': self.begin_comment,
            'end_from': datetime64_to_timestamp(self.end_from),
            'end_to': datetime64_to_timestamp(self.end_to),
            'end_comment': self.end_comment
        })

    def delete(self) -> None:
        Link.delete_(self.id)

    def set_dates(self, data: dict[str, Any]) -> None:
        self.begin_from = data['begin_from']
        self.begin_to = data['begin_to']
        self.begin_comment = data['begin_comment']
        self.end_from = data['end_from']
        self.end_to = data['end_to']
        self.end_comment = data['end_comment']

    @staticmethod
    def insert(entity: Entity,
               property_code: str,
               range_: Union[Entity, list[Entity]],
               description: Optional[str] = None,
               inverse: bool = False,
               type_id: Optional[int] = None) -> list[int]:
        property_ = g.properties[property_code]
        entities = range_ if isinstance(range_, list) else [range_]
        new_link_ids = []
        for linked_entity in entities:
            domain = linked_entity if inverse else entity
            range_ = entity if inverse else linked_entity
            domain_error = True
            range_error = True
            if property_.find_object('domain_class_code',
                                     domain.class_.cidoc_class.code):
                domain_error = False
            if property_.find_object('range_class_code',
                                     range_.class_.cidoc_class.code):
                range_error = False
            if domain_error or range_error:  # pragma: no cover
                text = \
                    f"invalid CIDOC link {domain.class_.cidoc_class.code}" \
                    f" > {property_code} > {range_.class_.cidoc_class.code}"
                logger.log('error', 'model', text)
                abort(400, text)
            id_ = Db.insert({
                'property_code': property_code,
                'domain_id': domain.id,
                'range_id': range_.id,
                'description': description,
                'type_id': type_id
            })
            new_link_ids.append(id_)
        return new_link_ids

    @staticmethod
    def get_linked_entity(id_: int,
                          code: str,
                          inverse: bool = False,
                          types: bool = False) -> Optional[Entity]:
        result = Link.get_linked_entities(id_,
                                          code,
                                          inverse=inverse,
                                          types=types)
        if len(result) > 1:  # pragma: no cover
            logger.log('error', 'model',
                       f'Multiple linked entities found for {code}')
            abort(400, 'Multiple linked entities found')
        return result[0] if result else None

    @staticmethod
    def get_linked_entities(id_: int,
                            codes: Union[str, list[str]],
                            inverse: bool = False,
                            types: bool = False) -> list[Entity]:
        from openatlas.models.entity import Entity
        codes = codes if isinstance(codes, list) else [codes]
        return Entity.get_by_ids(Db.get_linked_entities_inverse(
            id_, codes) if inverse else Db.get_linked_entities(id_, codes),
                                 types=types)

    @staticmethod
    def get_linked_entity_safe(id_: int,
                               code: str,
                               inverse: bool = False,
                               types: bool = False) -> Entity:
        entity = Link.get_linked_entity(id_, code, inverse, types)
        if not entity:  # pragma: no cover
            logger.log('error', 'model', 'missing linked',
                       f'id: {id_}, code: {code}')
            abort(418, f'Missing linked {code} for {id_}')
        return entity

    @staticmethod
    def get_links(entities: Union[int, list[int]],
                  codes: Union[str, list[str], None] = None,
                  inverse: bool = False) -> list[Link]:
        from openatlas.models.entity import Entity
        entity_ids = set()
        result = Db.get_links(
            entities, codes if isinstance(codes, list) else [str(codes)],
            inverse)
        for row in result:
            entity_ids.add(row['domain_id'])
            entity_ids.add(row['range_id'])
        linked_entities = {
            entity.id: entity
            for entity in Entity.get_by_ids(entity_ids, types=True)
        }
        links = []
        for row in result:
            links.append(
                Link(row,
                     domain=linked_entities[row['domain_id']],
                     range_=linked_entities[row['range_id']]))
        return links

    @staticmethod
    def delete_by_codes(entity: Entity,
                        codes: list[str],
                        inverse: bool = False) -> None:
        if entity.class_.name == 'stratigraphic_unit' \
                and 'P2' in codes \
                and not inverse:
            if anthropological_data := Anthropology.get_types(entity.id):
                Db.remove_types(
                    entity.id,
                    [row['link_id'] for row in anthropological_data])
                codes.remove('P2')
                if not codes:
                    return
        Db.delete_by_codes(entity.id, codes, inverse)
Пример #2
0
 def delete_by_codes(entity: 'Entity',
                     codes: List[str],
                     inverse: bool = False) -> None:
     Db.delete_by_codes(entity.id, codes, inverse)