Пример #1
0
    def _set_association(self, associate: Union[InternalIdModel, Iterable[InternalIdModel]],
                         associate_with: InternalIdModel, relationship_property_name: str):
        """
        Associates the given models to another model, linked to via the specified relationship property.
        :param associate: the models to associate
        :param associate_with: the model to associate with
        :param relationship_property_name: the property on `associate_with` in which the relationship is expressed
        """
        if associate_with.internal_id is None:
            raise ValueError("Model to associate with must have an internal ID: %s" % associate_with)

        if isinstance(associate, InternalIdModel):
            associate = [associate]

        session = self._database_connector.create_session()
        sqlalchemy_associated_with_type = get_equivalent_sqlalchemy_model_type(associate_with.__class__)
        assert sqlalchemy_associated_with_type is not None

        # sqlalchemy_associated_with_type = SQLAlchemyStudy
        results = session.query(sqlalchemy_associated_with_type). \
            filter(sqlalchemy_associated_with_type.internal_id == associate_with.internal_id).all()

        if len(results) != 1:
            raise ValueError("Model to associate with does not exist:\n%s" % associate_with)

        # FIXME: SQLAlchemy wants to insert the `associate` records. Could not find out how to stop this so hacking by
        #        deleting from the database. If the given model is not in sync with the  database this will lead to data
        #        loss.
        sqlalchemy_associate_type = get_equivalent_sqlalchemy_model_type(associate[0].__class__)
        assert sqlalchemy_associate_type is not None
        for associate_element in associate:
            session.query(sqlalchemy_associate_type).\
                filter(sqlalchemy_associate_type.internal_id == associate_element.internal_id).\
                delete()

        sqlalchemy_associate = convert_to_sqlalchemy_models(associate)
        for result in results:
            for sqlalchemy_associate_element in sqlalchemy_associate:
                current_relationship = getattr(result, relationship_property_name)
                if sqlalchemy_associate_element not in current_relationship:
                    setattr(result, relationship_property_name, current_relationship + sqlalchemy_associate)

        session.commit()
        session.close()
Пример #2
0
    def __init__(self, database_connector: SQLAlchemyDatabaseConnector, model_type: type):
        """
        Constructor.
        :param database_connector: the object through which database connections can be made
        :param model_type: the type of the model that the metadata_mapper is used for. Note that it is not (currently)
        possible in Python to get this type from the generic used
        """
        if not model_type:
            raise ValueError("Model type must be specified through `model_type` parameter")
        if not issubclass(model_type, Model):
            raise ValueError("Model type (%s) must be a subclass of `Model`" % model_type)

        self._database_connector = database_connector
        self._model_type = model_type
        self._sqlalchemy_model_type = get_equivalent_sqlalchemy_model_type(self._model_type)

        if self._sqlalchemy_model_type is None:
            raise NotImplementedError("Not implemented for models of type: `%s`" % model_type)
Пример #3
0
    def _get_association(self, associated_with: Union[InternalIdModel, Iterable[InternalIdModel]],
                         relationship_property_name: str) -> Sequence[_InternalIdMappedType]:
        """
        Gets the models that are associated to another model, linked to via the specified relationship property.
        :param associated_with: the model to find other models that are associated with it
        :param relationship_property_name: the property on `associated_with` in which the relationship is expressed
        :return: all models associated with the given `associated_with` model
        """
        if isinstance(associated_with, InternalIdModel):
            associated_with = [associated_with]
        if len(associated_with) == 0:
            return []

        session = self._database_connector.create_session()
        sqlalchemy_associated_with_type = get_equivalent_sqlalchemy_model_type(associated_with[0].__class__)
        assert sqlalchemy_associated_with_type is not None
        results = session.query(sqlalchemy_associated_with_type). \
            filter(sqlalchemy_associated_with_type.internal_id.
            in_([x.internal_id for x in associated_with])). \
            all()
        assert isinstance(results, collections.Sequence)

        if len(results) != len(associated_with):
            raise ValueError(
                "Not all given models to find associations with exist in the database.\nGiven: %s\nExisting: %s"
                % (associated_with, convert_to_popo_models(results)))

        associated = []
        for result in results:
            relationships = getattr(result, relationship_property_name)
            if not isinstance(relationships, list):
                relationships = [relationships]
            # Ensure only gets put in `associated` list once, even if the associate is associated with many of the given
            # `associated_with` models.
            for relationship in relationships:
                if relationship not in associated:
                    associated.append(relationship)
        session.close()

        return convert_to_popo_models(associated)
 def test_correct_with_multiplexed_library(self):
     self.assertEqual(get_equivalent_sqlalchemy_model_type(MultiplexedLibrary), SQLAlchemyMultiplexedLibrary)
 def test_correct_with_well(self):
     self.assertEqual(get_equivalent_sqlalchemy_model_type(Well), SQLAlchemyWell)
 def test_correct_with_library(self):
     self.assertEqual(get_equivalent_sqlalchemy_model_type(Library), SQLAlchemyLibrary)
 def test_correct_with_study(self):
     self.assertEqual(get_equivalent_sqlalchemy_model_type(Study), SQLAlchemyStudy)
 def test_correct_with_sample(self):
     self.assertEqual(get_equivalent_sqlalchemy_model_type(Sample), SQLAlchemySample)