Beispiel #1
0
class GroupRelationshipM2M(db.Model, Timestamp):
    """Many-to-many model for Group Relationships."""

    __tablename__ = 'grouprelationshipm2m'
    __table_args__ = (
        PrimaryKeyConstraint('relationship_id', 'subrelationship_id',
                             name='pk_grouprelationshipm2m'),
    )
    relationship_id = Column(UUIDType, ForeignKey(GroupRelationship.id,
                                                  onupdate="CASCADE",
                                                  ondelete="CASCADE"),
                             nullable=False)
    subrelationship_id = Column(UUIDType, ForeignKey(GroupRelationship.id,
                                                     onupdate="CASCADE",
                                                     ondelete="CASCADE"),
                                nullable=False)

    relationship = orm_relationship(GroupRelationship,
                                    foreign_keys=[relationship_id],
                                    backref='subrelationshipsm2m')
    subrelationship = orm_relationship(GroupRelationship,
                                       foreign_keys=[subrelationship_id],
                                       backref='superrelationshipsm2m')

    def __repr__(self):
        """String representation of the model."""
        return ('<{self.relationship}: {self.subrelationship}>'
                .format(self=self))
Beispiel #2
0
class Relationship2GroupRelationship(db.Model, Timestamp):
    """Many-to-many model for Relationship to GroupRelationship."""

    __tablename__ = 'relationship2grouprelationship'
    __table_args__ = (
        PrimaryKeyConstraint('relationship_id', 'group_relationship_id',
                             name='pk_relationship2grouprelationship'),
    )
    relationship_id = Column(UUIDType,
                             ForeignKey(Relationship.id, onupdate='CASCADE',
                                        ondelete='CASCADE'),
                             nullable=False)
    group_relationship_id = Column(UUIDType,
                                   ForeignKey(GroupRelationship.id,
                                              onupdate='CASCADE',
                                              ondelete='CASCADE'),
                                   nullable=False)

    # DB relationships
    relationship = orm_relationship(Relationship,
                                    foreign_keys=[relationship_id])
    group_relationship = orm_relationship(GroupRelationship,
                                          foreign_keys=[group_relationship_id])

    def __repr__(self):
        """String representation of the model."""
        return ('<{self.group_relationship}: {self.relationship}>'
                .format(self=self))
Beispiel #3
0
class GroupRelationship(db.Model, Timestamp):
    """Group relationship model."""

    __tablename__ = 'grouprelationship'
    __table_args__ = (
        UniqueConstraint('source_id', 'target_id', 'relation',
                         name='uq_grouprelationship_source_target_relation'),
        Index('ix_grouprelationship_source', 'source_id'),
        Index('ix_grouprelationship_target', 'target_id'),
        Index('ix_grouprelationship_relation', 'relation'),
    )

    id = Column(UUIDType, default=uuid.uuid4, primary_key=True)
    type = Column(Enum(GroupType), nullable=False)
    relation = Column(Enum(Relation), nullable=False)
    source_id = Column(UUIDType, ForeignKey(Group.id, ondelete='CASCADE',
                                            onupdate='CASCADE'),
                       nullable=False)
    target_id = Column(UUIDType, ForeignKey(Group.id, ondelete='CASCADE',
                                            onupdate='CASCADE'),
                       nullable=False)

    # DB relationships
    source = orm_relationship(
        Group, foreign_keys=[source_id], backref='sources')
    target = orm_relationship(
        Group, foreign_keys=[target_id], backref='targets')

    relationships = orm_relationship(
        'GroupRelationship',
        secondary=lambda: GroupRelationshipM2M.__table__,
        primaryjoin=lambda: (GroupRelationship.id ==
                             GroupRelationshipM2M.relationship_id),
        secondaryjoin=lambda: (GroupRelationship.id ==
                               GroupRelationshipM2M.subrelationship_id))

    # TODO:
    # We don't store 'deleted' as in the relation as most likely don't need
    # that as 'ground truth' in precomputed groups anyway

    def __repr__(self):
        """String representation of the group relationship."""
        return ('<{self.source} {self.relation.name} {self.target}>'
                .format(self=self))
Beispiel #4
0
class GroupRelationshipMetadata(db.Model, Timestamp):
    """Metadata for a group relationship."""

    __tablename__ = 'grouprelationshipmetadata'

    # TODO: assert group_relationship.type == GroupType.Identity
    group_relationship_id = Column(
        UUIDType,
        ForeignKey(GroupRelationship.id,
                   onupdate='CASCADE',
                   ondelete='CASCADE'),
        primary_key=True)
    group_relationship = orm_relationship(
        GroupRelationship,
        backref=backref('data', uselist=False),
        single_parent=True,
    )
    json = Column(
        JSON()
        .with_variant(postgresql.JSONB(none_as_null=True), 'postgresql')
        .with_variant(JSONType(), 'sqlite'),
        default=list,
    )

    # Relationship metadata
    SCHEMA = {
        '$schema': 'http://json-schema.org/draft-06/schema#',
        'definitions': COMMON_SCHEMA_DEFINITIONS,
        'type': 'array',
        'items': {
            'type': 'object',
            'additionalProperties': False,
            'properties': {
                'LinkPublicationDate': {'$ref': '#/definitions/DateType'},
                'LinkProvider': {
                    'type': 'array',
                    'items': {'$ref': '#/definitions/PersonOrOrgType'}
                },
                'LicenseURL': {'type': 'string'},
            },
            'required': ['LinkPublicationDate', 'LinkProvider'],
        }
    }

    def update(self, payload, validate=True, multi=False):
        """Updates the metadata of a group relationship."""
        new_json = deepcopy(self.json or [])
        if multi:
            new_json.extend(payload)
        else:
            new_json.append(payload)
        if validate:
            jsonschema.validate(new_json, self.SCHEMA)
        self.json = new_json
        flag_modified(self, 'json')
        return self
Beispiel #5
0
class Identifier2Group(db.Model, Timestamp):
    """Many-to-many model for Identifier and Group."""

    __tablename__ = 'identifier2group'
    __table_args__ = (
        PrimaryKeyConstraint('identifier_id', 'group_id',
                             name='pk_identifier2group'),
    )
    identifier_id = Column(UUIDType, ForeignKey(Identifier.id,
                                                ondelete='CASCADE',
                                                onupdate='CASCADE'),
                           nullable=False)
    group_id = Column(UUIDType, ForeignKey(Group.id, ondelete='CASCADE',
                                           onupdate='CASCADE'),
                      nullable=False)

    # DB relationships
    identifier = orm_relationship(Identifier, foreign_keys=[identifier_id],
                                  backref='id2groups')
    group = orm_relationship(Group, foreign_keys=[group_id],
                             backref='id2groups')
Beispiel #6
0
class Group(db.Model, Timestamp):
    """Group model."""

    __tablename__ = 'group'

    id = Column(UUIDType, default=uuid.uuid4, primary_key=True)
    type = Column(Enum(GroupType), nullable=False)

    identifiers = orm_relationship(
        Identifier,
        secondary=lambda: Identifier2Group.__table__,
        backref='groups',
        viewonly=True)

    groups = orm_relationship(
        'Group',
        secondary=lambda: GroupM2M.__table__,
        primaryjoin=lambda: (Group.id == GroupM2M.group_id),
        secondaryjoin=lambda: (Group.id == GroupM2M.subgroup_id))

    def __repr__(self):
        """String representation of the group."""
        return "<{self.id}: {self.type.name}>".format(self=self)
Beispiel #7
0
class GroupMetadata(db.Model, Timestamp):
    """Metadata for a group."""

    __tablename__ = 'groupmetadata'

    # TODO: assert group.type == GroupType.Identity
    group_id = Column(
        UUIDType,
        ForeignKey(Group.id, onupdate='CASCADE', ondelete='CASCADE'),
        primary_key=True)
    group = orm_relationship(
        Group,
        backref=backref('data', uselist=False),
        single_parent=True,
    )
    json = Column(
        JSON()
        .with_variant(postgresql.JSONB(none_as_null=True), 'postgresql')
        .with_variant(JSONType(), 'sqlite'),
        default=dict,
    )

    # Identifier metadata
    SCHEMA = {
        '$schema': 'http://json-schema.org/draft-06/schema#',
        'definitions': COMMON_SCHEMA_DEFINITIONS,
        'additionalProperties': False,
        'properties': {
            k: v for k, v in OBJECT_TYPE_SCHEMA['properties'].items()
            if k in OVERRIDABLE_KEYS
        },
    }

    def update(self, payload, validate=True):
        """Update the metadata of a group."""
        new_json = deepcopy(self.json or {})
        for k in OVERRIDABLE_KEYS:
            if payload.get(k):
                if k == 'Type' and not _is_type_overridable(payload):
                    continue
                new_json[k] = payload[k]
        if validate:
            jsonschema.validate(new_json, self.SCHEMA)
        self.json = new_json
        flag_modified(self, 'json')
        return self
Beispiel #8
0
class Relationship(db.Model, Timestamp):
    """Relationship between two identifiers."""

    __tablename__ = 'relationship'
    __table_args__ = (
        UniqueConstraint('source_id', 'target_id', 'relation',
                         name='uq_relationship_source_target_relation'),
        Index('ix_relationship_source', 'source_id'),
        Index('ix_relationship_target', 'target_id'),
        Index('ix_relationship_relation', 'relation'),
    )

    id = Column(UUIDType, default=uuid.uuid4, primary_key=True)
    source_id = Column(UUIDType,
                       ForeignKey(Identifier.id, onupdate='CASCADE',
                                  ondelete='CASCADE',
                                  name='fk_relationship_source'),
                       nullable=False)
    target_id = Column(UUIDType, ForeignKey(Identifier.id, onupdate='CASCADE',
                                            ondelete='CASCADE',
                                            name='fk_relationship_target'),
                       nullable=False)
    relation = Column(Enum(Relation))

    source = orm_relationship(Identifier, foreign_keys=[source_id],
                              backref='sources')
    target = orm_relationship(Identifier, foreign_keys=[target_id],
                              backref='targets')

    @classmethod
    def get(cls, source, target, relation, **kwargs):
        """Get the relationship from the database."""
        return cls.query.filter_by(
            source_id=source.id, target_id=target.id,
            relation=relation).one_or_none()

    def fetch_or_create_id(self):
        """Fetches from the database or creates an id for the relationship."""
        self.source = self.source.fetch_or_create_id()
        self.target = self.target.fetch_or_create_id()

        if not self.id:
            obj = self.get(self.source, self.target, self.relation)
            if obj:
                self = obj
            else:
                self.id = uuid.uuid4()
        return self

    @property
    def identity_group(self):
        """Get the relationship's identity group."""
        return GroupRelationship.query.filter_by(
            source=self.source.identity_group,
            target=self.target.identity_group,
            relation=self.relation,
            type=GroupType.Identity).one_or_none()

    @property
    def data(self):
        """Get the relationship's identity group metadata."""
        if self.identity_group and self.identity_group.data:
            return self.identity_group.data.json

    def __repr__(self):
        """String representation of the relationship."""
        return (
            '<{self.source.value} {self.relation.name} '
            '{self.target.value}>'.format(self=self)
        )