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)
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" )
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")
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)
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)
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)
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)
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 )
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]
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]
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]