Пример #1
0
def create_connection_model(services):
    """ Create an SQL Alchemy table that connects the provides services """

    # the mixins / base for the model
    bases = HasID, BaseModel
    # the fields of the derived
    attributes = {service.name: Column(Text, nullable = False) for service in services}

    # create an instance of base model with the right attributes
    return type(BaseModel)(connection_service_name(*services), bases, attributes)
Пример #2
0
    def test_connection_service_name(self):
        # two models to test

        # a connection service for both
        class Connection(nautilus.ConnectionService):
            to_service = ('TestService1',)
            from_service = ('TestService2',)
        # make sure we could make a name
        assert isinstance(conventions.connection_service_name(Connection()), str), (
            "Could not generate name for connection service"
        )
Пример #3
0
    def test_connection_service_name(self):
        # two models to test

        # a connection service for both
        class Connection(nautilus.ConnectionService):
            to_service = ('TestService1', )
            from_service = ('TestService2', )

        # make sure we could make a name
        assert isinstance(
            conventions.connection_service_name(Connection()),
            str), ("Could not generate name for connection service")
Пример #4
0
def create_connection_model(service):
    """ Create an SQL Alchemy table that connects the provides services """
    # the services connected
    services = service._services

    # the mixins / base for the model
    bases = (BaseModel,)
    # the fields of the derived
    attributes = {model_service_name(service): fields.CharField() for service in services}

    # create an instance of base model with the right attributes
    return type(BaseModel)(connection_service_name(service), bases, attributes)
Пример #5
0
def create_connection_model(services):
    """ Create an SQL Alchemy table that connects the provides services """

    # the mixins / base for the model
    bases = HasID, BaseModel
    # the fields of the derived
    attributes = {
        service.name: Column(Text, nullable=False)
        for service in services
    }

    # create an instance of base model with the right attributes
    return type(BaseModel)(connection_service_name(*services), bases,
                           attributes)
Пример #6
0
    def __init__(self,
                 services,
                 additonal_action_handler=noop_handler,
                 **kwargs):

        # *sigh*
        from nautilus.models import create_connection_model

        # make sure we were passed more than one service
        if len(services) < 2:
            raise Exception("Please provide more than one service to connect")

        # # create the service
        super().__init__(model=create_connection_model(services),
                         name=connection_service_name(*services),
                         **kwargs)
Пример #7
0
    def __init__(self, **kwargs):

        # if there is no to service
        if not self.to_service:
            raise ValueError("Please provide a 'to_service'.")
        # if there is no to service
        if not self.from_service:
            raise ValueError("Please provide a 'from_service'.")

        # save a list of the models
        self._services = [self.to_service[0], self.from_service[0]]

        # make sure there is a unique name for every service
        if len(set(self._services)) != len(self._services):
            raise ValueError("Can only connect models with different name")

        # create the service
        super().__init__(model=create_connection_model(self),
                         name=connection_service_name(self),
                         **kwargs)
Пример #8
0
    def __init__(self, **kwargs):

        # if there is no to service
        if not self.to_service:
            raise ValueError("Please provide a 'to_service'.")
        # if there is no to service
        if not self.from_service:
            raise ValueError("Please provide a 'from_service'.")

        # save a list of the models
        self._services = [self.to_service[0], self.from_service[0]]

        # make sure there is a unique name for every service
        if len(set(self._services)) != len(self._services):
            raise ValueError("Can only connect models with different name")

        # create the service
        super().__init__(
            model=create_connection_model(self),
            name=connection_service_name(self),
            **kwargs
        )
Пример #9
0
    def resolve_service(self, instance, query_args, info):
        '''
            This function grab the remote data that acts as the source for this
            connection.
        '''
        # note: it is safe to assume the target is a service object

        # the target class for the connection
        target = self.target

        # if we were given a string to target
        if isinstance(target, str):
            # if the string points to a service object we recognize
            if target in serivce_objects:
                # grab the service object with the matching name
                target = serivce_objects[target]
            # otherwise the string target does not designate a service object
            else:
                # yell loudly
                raise ValueError("Please provide a string designating a " + \
                                    "ServiceObjectType as the target for " + \
                                    "a connection.")

        # make a normal dictionary out of the immutable one we were given
        args = query_args \
                    if isinstance(query_args, dict) \
                    else query_args.to_data_dict()

        ## resolve the connection if necessary
        target_service_name = target.service.name \
                                    if hasattr(target.service, 'name') \
                                    else target.service

        # if we are connecting two service objects, we need to go through a connection table
        if isinstance(instance, ServiceObjectType) or isinstance(instance, str):
            # the target service
            instance_service_name = instance.service.name \
                                            if hasattr(instance.service, 'name') \
                                            else instance.service

            # the name of the service that manages the connection
            connection_service = connection_service_name(target_service_name,
                                                         instance_service_name)

            # look for connections originating from this object
            join_filter = {}
            join_filter[instance_service_name] = instance.primary_key

            # query the connection service for related data
            related = query_service(
                connection_service,
                [target_service_name],
                join_filter
            )

            # if there were no related fields
            if len(related) == 0:
                return []

            # grab the list of primary keys from the remote service
            join_ids = [entry[target_service_name] for entry in related]

            # add the private key filter to the filter dicts
            args['pk_in'] = join_ids

        ## query the target service

        # only query the backend service for the fields that are not connections
        fields = [field.attname for field in target.true_fields()]

        # grab the final list of entries
        results = query_service(target_service_name, fields, filters=args)

        # there are no results
        if len(results) == 0:
            return []
        # if there is more than one result for a "one" relation
        elif len(results) > 1 and self.relationship == 'one':
            # yell loudly
            raise Exception("Inconsistent state reached: multiple entries " + \
                                        "resolving a foreign key reference")

        ## remove instances of the target that the user is not allowed to see

        # if we need to apply some sort of authorization
        if hasattr(target, 'auth'):
            # apply the authorization criteria to the result
            results = [result for result in results \
                                if target.auth(target(**result), current_user)]

        ## deal with target relationship types

        # if the filter got rid of all of the results
        if len(results) == 0:
            # the user isn't allowed to see the related data so return nothing
            return None

        # todo: think about doing this at the join step
        # (how to specify both sides of relationship in one spot)
        # if we are on the `one` side of the relationship
        elif self.relationship == 'one':
            # pull the first item out of the list
            return target(**results[0])

        # create instances of the target class for every result
        return [target(**result) for result in results]
Пример #10
0
    def resolve_service(self, args, context, info):
        '''
            This function grab the remote data that acts as the source for this
            connection.

            Note: it is safe to assume the target is a service object -
                strings have been coerced.
        '''
        # note: it is safe to assume the target is a service object
        ## resolve the connection if necessary
        target_service_name = self._service_name(self.target)

        # if we are connecting two service objects, we need to go through a connection table
        if isinstance(self, ServiceObjectType):

            # the target service
            instance_service_name = self._service_name(self)

            # the name of the service that manages the connection
            connection_service = connection_service_name(target_service_name,
                                                         instance_service_name)
            # the primary key of the instance we are refering from
            instance_pk = getattr(self, self.service.model.primary_key().name)
            # look for connections originating from this object
            join_filter = {instance_service_name: instance_pk}

            # query the connection service for related data
            related = context.service.query_service(
                connection_service,
                [target_service_name],
                filters=join_filter
            )

            # if there were no related fields
            if len(related) == 0:
                return []

            # grab the list of primary keys from the remote service
            join_ids = [entry[target_service_name] for entry in related]
            # add the private key filter to the filter dicts
            args['pk_in'] = join_ids

        ## query the target service

        # only query the backend service for the fields that are not connections
        fields = [field.attname for field in self.target.true_fields()]
        # grab the final list of entries
        results = context.service.query_service(
            target_service_name,
            fields,
            filters=args
        )

        # there are no results
        if len(results) == 0:
            # return an empty result
            return []
        # if there is more than one result for a "one" relation
        elif len(results) > 1 and self.relationship == 'one':
            # yell loudly
            raise ValueError("Inconsistent state reached: multiple entries " + \
                                        "resolving a foreign key reference")

        ## remove instances of the target that the user is not allowed to see
        # if we need to apply some sort of authorization
        if hasattr(self.target, 'auth'):

            try:
                # grab the current user from the request_context
                current_user = context.current_user
            # if there is no user
            except AttributeError:
                raise Exception("User is not accessible.")

            # if the current reqeust is not logged in
            if not current_user:
                # yell loudly
                raise ValueError("User is not logged in.")

            # apply the authorization criteria to the result
            results = [
                result for result in results \
                if self.target.auth(
                    self.target(**result),
                    current_user.decode('utf-8')
                )
            ]

        ## deal with target relationship types

        # if the filter got rid of all of the results
        if len(results) == 0:
            # the user isn't allowed to see the related data so return nothing
            return None

        # todo: think about doing this at the join step
        # (how to specify both sides of relationship in one spot)

        # if we are on the `one` side of the relationship
        elif self.relationship == 'one':
            # pull the first item out of the list
            return self.target(**results[0])

        # create instances of the target class for every result
        return [self.target(**result) for result in results]
Пример #11
0
    def resolve_service(self, instance, query_args, info):
        '''
            This function grab the remote data that acts as the source for this
            connection.
        '''
        # note: it is safe to assume the target is a service object

        # the target class for the connection
        target = self.target

        # if we were given a string to target
        if isinstance(target, str):
            # if the string points to a service object we recognize
            if target in serivce_objects:
                # grab the service object with the matching name
                target = serivce_objects[target]
            # otherwise the string target does not designate a service object
            else:
                # yell loudly
                raise ValueError("Please provide a string designating a " + \
                                    "ServiceObjectType as the target for " + \
                                    "a connection.")

        # make a normal dictionary out of the immutable one we were given
        args = query_args \
                    if isinstance(query_args, dict) \
                    else query_args.to_data_dict()

        ## resolve the connection if necessary
        target_service_name = target.service.name \
                                    if hasattr(target.service, 'name') \
                                    else target.service

        # if we are connecting two service objects, we need to go through a connection table
        if isinstance(instance, ServiceObjectType) or isinstance(
                instance, str):
            # the target service
            instance_service_name = instance.service.name \
                                            if hasattr(instance.service, 'name') \
                                            else instance.service

            # the name of the service that manages the connection
            connection_service = connection_service_name(
                target_service_name, instance_service_name)

            # look for connections originating from this object
            join_filter = {}
            join_filter[instance_service_name] = instance.primary_key

            # query the connection service for related data
            related = query_service(connection_service, [target_service_name],
                                    join_filter)

            # if there were no related fields
            if len(related) == 0:
                return []

            # grab the list of primary keys from the remote service
            join_ids = [entry[target_service_name] for entry in related]

            # add the private key filter to the filter dicts
            args['pk_in'] = join_ids

        ## query the target service

        # only query the backend service for the fields that are not connections
        fields = [field.attname for field in target.true_fields()]

        # grab the final list of entries
        results = query_service(target_service_name, fields, filters=args)

        # there are no results
        if len(results) == 0:
            return []
        # if there is more than one result for a "one" relation
        elif len(results) > 1 and self.relationship == 'one':
            # yell loudly
            raise Exception("Inconsistent state reached: multiple entries " + \
                                        "resolving a foreign key reference")

        ## remove instances of the target that the user is not allowed to see

        # if we need to apply some sort of authorization
        if hasattr(target, 'auth'):
            # apply the authorization criteria to the result
            results = [result for result in results \
                                if target.auth(target(**result), current_user)]

        ## deal with target relationship types

        # if the filter got rid of all of the results
        if len(results) == 0:
            # the user isn't allowed to see the related data so return nothing
            return None

        # todo: think about doing this at the join step
        # (how to specify both sides of relationship in one spot)
        # if we are on the `one` side of the relationship
        elif self.relationship == 'one':
            # pull the first item out of the list
            return target(**results[0])

        # create instances of the target class for every result
        return [target(**result) for result in results]