Beispiel #1
0
 def loader_options(self):
     """
     Dictionary mapping each entity class to configure a loader for to a
     list of (possibly nested) entity attribute names.
     """
     all_keys = set(self.__attr_map.keys())
     # Go through the collected keys and through out all keys which are
     # subkeys of others to eliminate redundancy.
     for key in sorted(self.__attr_map):
         for idx in range(1, len(key)):
             sub_key = key[:-idx]
             if sub_key in all_keys:
                 all_keys.remove(sub_key)
     if provides_member_resource(self._context):
         # If the context is a member, we need to configure the loaders
         # for the entity class belonging to each of its resource
         # attributes. Only nested keys collected from the representer
         # configuration need to be configured (and the corresponding
         # nested entity attribute needs to be shortened).
         loader_option_map = defaultdict(list)
         for key in all_keys:
             entity_attr_names = self.__attr_map[key]
             if len(entity_attr_names) > 1:
                 ent_attr_name = entity_attr_names[0]
                 nested_attr_name = '.'.join(entity_attr_names[1:])
                 opts = loader_option_map[ent_attr_name]
                 opts.append(nested_attr_name)
         # Translate to entity classes as keys. This is tricky as the
         # keys in the loader option map can itself be nested attributes.
         for ent_attr_name, nested_attr_names in loader_option_map.items():
             ent_attr_name_tokens = ent_attr_name.split('.')
             ent_cls = get_entity_class(self._context)
             ent_cls_attr = getattr(ent_cls, ent_attr_name_tokens[0])
             ent_cls = ent_cls_attr.property.mapper.entity
             if len(ent_attr_name_tokens) > 1:
                 prefix = '.'.join(ent_attr_name_tokens[1:])
                 loader_option_map[ent_cls] = \
                         ["%s.%s" % (prefix, token)
                          for token in nested_attr_names]
             else:
                 loader_option_map[ent_cls] = nested_attr_names
             del loader_option_map[ent_attr_name]
     else:
         # If the context is a collection, we need to configure the
         # loader for its entity class.
         loader_option_map = {get_entity_class(self._context) :
                              ['.'.join(self.__attr_map[key])
                               for key in all_keys]}
     return loader_option_map
Beispiel #2
0
 def visit_member(self, attribute_key, attribute, member_node, member_data,
                  is_link_node, parent_data, index=None):
     if is_link_node:
         url = member_node.get_url()
         rc = url_to_resource(url)
         entity = rc.get_entity()
     else:
         entity_cls = get_entity_class(member_node.mapping.mapped_class)
         entity_data = {}
         nested_entity_data = {}
         for attr, value in member_data.iteritems():
             if '.' in attr.entity_name:
                 nested_entity_data[attr.entity_name] = value
             else:
                 entity_data[attr.entity_name] = value
         entity = entity_cls.create_from_data(entity_data)
         # Set nested attribute values.
         # FIXME: lazy loading of nested attributes is not supported.
         for nested_attr, value in nested_entity_data.iteritems():
             tokens = nested_attr.split('.')
             parent = reduce(getattr, tokens[:-1], entity)
             if not parent is None:
                 setattr(parent, tokens[-1], value)
     if not index is None:
         # Collection member. Store in parent data with index as key.
         parent_data[index] = entity
     elif len(attribute_key) == 0:
         # Top level. Store root entity and create resource.
         mapped_cls = member_node.mapping.mapped_class
         self.__resource = mapped_cls.create_from_entity(entity)
     else:
         # Nested member. Store in parent data with attribute as key.
         parent_data[attribute] = entity
Beispiel #3
0
 def inspect(entity_class, attribute_name):
     attr_tokens = attribute_name.split('.')
     infos = []
     for idx, attr_token in enumerate(attr_tokens):
         do_append = True
         try:
             attr = get_domain_class_attributes(entity_class)[attr_token]
         except KeyError:
             if attr_token != 'slug':
                 # If we encounter a non-resource attribute, we assume
                 # an embedded document (which implies that the last
                 # token was a terminal).
                 infos[-1][-1] = \
                     '.'.join([infos[-1][-1]] + attr_tokens[idx:])
                 # Unfortunately, we can not infer the type of embedded
                 # attributes.
                 infos[-1][1] = None
                 do_append = False
             else:
                 # The 'slug' attribute is special as it is not a properly
                 # declared resource attribute but needs to be queryable.
                 attr_kind = RESOURCE_ATTRIBUTE_KINDS.TERMINAL
                 attr_type = str
         else:
             attr_kind = attr.kind
             if attr_kind != RESOURCE_ATTRIBUTE_KINDS.TERMINAL:
                 entity_class = get_entity_class(attr.attr_type)
                 attr_type = entity_class
             else:
                 attr_type = attr.attr_type
         if do_append:
             infos.append([attr_kind, attr_type, attr_token])
     return infos
Beispiel #4
0
 def __clone(self, entity, cache):
     clone = object.__new__(entity.__class__)
     # We add the clone with its ID set to the cache *before* we load it
     # so that circular references will work.
     clone.id = entity.id
     cache.add(clone)
     state = EntityState.get_state_data(entity)
     id_attr = None
     for attr, value in iteritems_(state):
         if attr.entity_attr == 'id':
             id_attr = attr
             continue
         attr_type = attr.attr_type
         if attr.kind != RESOURCE_ATTRIBUTE_KINDS.TERMINAL \
            and not self.__repository.is_registered_resource(attr_type):
             # Prevent loading of entities from other repositories.
             # FIXME: Doing this here is inconsistent, since e.g. the RDB
             #        session does not perform this kind of check.
             continue
         elif attr.kind == RESOURCE_ATTRIBUTE_KINDS.MEMBER \
            and not value is None:
             ent_cls = get_entity_class(attr_type)
             new_value = self.load(ent_cls, value)
             state[attr] = new_value
         elif attr.kind == RESOURCE_ATTRIBUTE_KINDS.COLLECTION \
              and len(value) > 0:
             value_type = type(value)
             new_value = value_type.__new__(value_type)
             if issubclass(value_type, MutableSequence):
                 add_op = new_value.append
             elif issubclass(value_type, MutableSet):
                 add_op = new_value.add
             else:
                 raise ValueError('Do not know how to clone value of type '
                                  '%s for resource attribute %s.' %
                                  (type(new_value), attr))
             ent_cls = get_entity_class(attr_type)
             for child in value:
                 child_clone = self.load(ent_cls, child)
                 add_op(child_clone)
             state[attr] = new_value
     # We set the ID already above.
     if not id_attr is None:
         del state[id_attr]
     EntityState.set_state_data(clone, state)
     return clone
Beispiel #5
0
 def __clone(self, entity, cache):
     clone = object.__new__(entity.__class__)
     # We add the clone with its ID set to the cache *before* we load it
     # so that circular references will work.
     clone.id = entity.id
     cache.add(clone)
     state = EntityState.get_state_data(entity)
     id_attr = None
     for attr, value in iteritems_(state):
         if attr.entity_attr == 'id':
             id_attr = attr
             continue
         attr_type = attr.attr_type
         if attr.kind != RESOURCE_ATTRIBUTE_KINDS.TERMINAL \
            and not self.__repository.is_registered_resource(attr_type):
             # Prevent loading of entities from other repositories.
             # FIXME: Doing this here is inconsistent, since e.g. the RDB
             #        session does not perform this kind of check.
             continue
         elif attr.kind == RESOURCE_ATTRIBUTE_KINDS.MEMBER \
            and not value is None:
             ent_cls = get_entity_class(attr_type)
             new_value = self.load(ent_cls, value)
             state[attr] = new_value
         elif attr.kind == RESOURCE_ATTRIBUTE_KINDS.COLLECTION \
              and len(value) > 0:
             value_type = type(value)
             new_value = value_type.__new__(value_type)
             if issubclass(value_type, MutableSequence):
                 add_op = new_value.append
             elif issubclass(value_type, MutableSet):
                 add_op = new_value.add
             else:
                 raise ValueError('Do not know how to clone value of type '
                                  '%s for resource attribute %s.'
                                  % (type(new_value), attr))
             ent_cls = get_entity_class(attr_type)
             for child in value:
                 child_clone = self.load(ent_cls, child)
                 add_op(child_clone)
             state[attr] = new_value
     # We set the ID already above.
     if not id_attr is None:
         del state[id_attr]
     EntityState.set_state_data(clone, state)
     return clone
Beispiel #6
0
 def __collect(self, resource):
     ent_cls = get_entity_class(resource)
     coll_cls = get_collection_class(resource)
     cache = EntityCacheMap()
     agg = StagingAggregate(ent_cls, cache)
     coll = coll_cls.create_from_aggregate(agg)
     coll.add(resource)
     return dict([(get_member_class(ent_cls),
                   coll.get_root_collection(ent_cls))
                  for ent_cls in cache.keys()])
Beispiel #7
0
 def __collect(self, resource):
     ent_cls = get_entity_class(resource)
     coll_cls = get_collection_class(resource)
     cache = EntityCacheMap()
     agg = StagingAggregate(ent_cls, cache)
     coll = coll_cls.create_from_aggregate(agg)
     coll.add(resource)
     return dict([(get_member_class(ent_cls),
                   coll.get_root_collection(ent_cls))
                  for ent_cls in cache.keys()])
Beispiel #8
0
def create_staging_collection(resource):
    """
    Helper function to create a staging collection for the given registered
    resource.

    :param resource: registered resource
    :type resource: class implementing or instance providing or subclass of
        a registered resource interface.
    """
    ent_cls = get_entity_class(resource)
    coll_cls = get_collection_class(resource)
    agg = StagingAggregate(ent_cls)
    return coll_cls.create_from_aggregate(agg)
Beispiel #9
0
def create_staging_collection(resource):
    """
    Helper function to create a staging collection for the given registered
    resource.

    :param resource: registered resource
    :type resource: class implementing or instance providing or subclass of
        a registered resource interface.
    """
    ent_cls = get_entity_class(resource)
    coll_cls = get_collection_class(resource)
    agg = StagingAggregate(ent_cls)
    return coll_cls.create_from_aggregate(agg)
Beispiel #10
0
 def set_collection_parent(self, resource, parent):
     """
     Sets the parent of the specified root collection to the given
     object (typically a service object).
     
     :param resource: Registered resource.
     :raises ValueError: If no root collection has been created for the
       given registered resource.
     """
     ent_cls = get_entity_class(resource)
     root_coll = self.__cache.get(ent_cls)
     if root_coll is None:
         raise ValueError('No root collection available for resource.')
     root_coll.__parent__ = parent
Beispiel #11
0
 def get_collection(self, resource):
     if not self.__is_initialized:
         raise RuntimeError('Repository needs to be initialized.')
     ent_cls = get_entity_class(resource)
     root_coll = self.__cache.get(ent_cls)
     if root_coll is None:
         # Create a new root aggregate.
         root_agg = self.__agg_cls.create(ent_cls, self.session_factory,
                                          self)
         # Create a new root collection.
         coll_cls = get_collection_class(resource)
         root_coll = coll_cls.create_from_aggregate(root_agg)
         self.__cache[ent_cls] = root_coll
     return root_coll.clone()
Beispiel #12
0
    def set_collection_parent(self, resource, parent):
        """
        Sets the parent of the specified root collection to the given
        object (typically a service object).

        :param resource: Registered resource.
        :raises ValueError: If no root collection has been created for the
          given registered resource.
        """
        ent_cls = get_entity_class(resource)
        root_coll = self.__cache.get(ent_cls)
        if root_coll is None:
            raise ValueError('No root collection available for resource.')
        root_coll.__parent__ = parent
Beispiel #13
0
 def get_collection(self, resource):
     if not self.__is_initialized:
         raise RuntimeError('Repository needs to be initialized.')
     ent_cls = get_entity_class(resource)
     root_coll = self.__cache.get(ent_cls)
     if root_coll is None:
         # Create a new root aggregate.
         root_agg = self.__agg_cls.create(ent_cls, self.session_factory,
                                          self)
         # Create a new root collection.
         coll_cls = get_collection_class(resource)
         root_coll = coll_cls.create_from_aggregate(root_agg)
         self.__cache[ent_cls] = root_coll
     return root_coll.clone()
Beispiel #14
0
 def __get__(self, entity, entity_class):
     if not entity is None:
         ref_val = entity.__mongo_refs__[self.__attr.entity_attr]
         attr_entity_class = get_entity_class(self.__attr.attr_type)
         if isinstance(ref_val, list):
             # FIXME: Assuming list here.
             value = [transform_outgoing(attr_entity_class,
                                         self.__db.dereference(el))
                      for el in ref_val]
         else:
             value = transform_outgoing(attr_entity_class,
                                        self.__db.dereference(ref_val))
         setattr(entity, self.__attr.entity_attr, value)
     else:
         value = self
     return value
Beispiel #15
0
 def __load_entities(self, entity_class, is_top_level):
     # Check if we have an entity loader configured.
     loader = self.configuration['cache_loader']
     if not loader is None:
         cache = self.__cache_map[entity_class]
         for ent in loader(entity_class):
             if ent.id is None:
                 ent.id = new_entity_id()
             cache.add(ent)
         # To fully initialize the cache, we also need to load collections
         # that are not linked to from any of the entities just loaded.
         if is_top_level:
             for reg_rc in self.registered_resources:
                 reg_ent_cls = get_entity_class(reg_rc)
                 if not reg_ent_cls in self.__cache_map:
                     self.__load_entities(reg_ent_cls, False)
Beispiel #16
0
 def _initialize(self):
     if not is_engine_initialized(self.name):
         engine = self.__make_engine()
         set_engine(self.name, engine)
     else:
         engine = get_engine(self.name)
     db_name = self._config['db_name']
     self.__db = operator.getitem(engine, db_name)
     if db_name == 'test':
         # Reset the test database.
         for coll_name in \
           self.__db.collection_names(include_system_collections=False):
             self.__db.drop_collection(coll_name)
     # Set up the class registry.
     for rc in self.registered_resources:
         ent_cls = get_entity_class(rc)
         if not MongoClassRegistry.is_registered(ent_cls):
             MongoClassRegistry.register(ent_cls, self.__db)
Beispiel #17
0
    def get_collection(self, resource):
        """
        Get a clone of the root collection for the given registered resource.

        :param resource: Registered resource.
        :raises RuntimeError: If the repository has not been initialized yet.
        """
        if not self.__is_initialized:
            raise RuntimeError('Repository needs to be initialized.')
        ent_cls = get_entity_class(resource)
        root_coll = self.__cache.get(ent_cls)
        if root_coll is None:
            coll_cls = get_collection_class(resource)
            agg = self.__agg_cls.create(ent_cls, self.session_factory)
            root_coll = coll_cls.create_from_aggregate(agg)
            self.__cache[ent_cls] = root_coll
        clone = root_coll.clone()
        clone.__repository__ = self
        return clone
Beispiel #18
0
    def get_collection(self, resource):
        """
        Get a clone of the root collection for the given registered resource.

        :param resource: Registered resource.
        :raises RuntimeError: If the repository has not been initialized yet.
        """
        if not self.__is_initialized:
            raise RuntimeError('Repository needs to be initialized.')
        ent_cls = get_entity_class(resource)
        root_coll = self.__cache.get(ent_cls)
        if root_coll is None:
            coll_cls = get_collection_class(resource)
            agg = self.__agg_cls.create(ent_cls, self.session_factory)
            root_coll = coll_cls.create_from_aggregate(agg)
            self.__cache[ent_cls] = root_coll
        clone = root_coll.clone()
        clone.__repository__ = self
        return clone
Beispiel #19
0
    def __init__(self, entity, name=None, relationship=None):
        """
        Constructor:

        :param str name: Unique name of the member within the collection
        :param entity: Associated entity (domain object).
        :type entity: Object implementing an interface derived from
                :class:`everest.entities.interfaces.IEntity`.
        """
        if self.__class__ is Member:
            raise NotImplementedError('Abstract class')
        if not isinstance(entity, get_entity_class(self)):
            raise ValueError(
                    'Invalid entity class "%s" for %s resource class.'
                    % (entity.__class__.__name__, self.__class__.__name__))
        super(Member, self).__init__(relationship=relationship)
        self.__entity = entity
        self.__name = name
        # Add the rel="self" link.
        self.add_link(Link(self, "self"))
Beispiel #20
0
    def __init__(self, entity, name=None, relationship=None):
        """
        Constructor:

        :param str name: Unique name of the member within the collection
        :param entity: Associated entity (domain object).
        :type entity: Object implementing an interface derived from
                :class:`everest.entities.interfaces.IEntity`.
        """
        if self.__class__ is Member:
            raise NotImplementedError('Abstract class')
        if not isinstance(entity, get_entity_class(self)):
            raise ValueError(
                'Invalid entity class "%s" for %s resource class.' %
                (entity.__class__.__name__, self.__class__.__name__))
        super(Member, self).__init__(relationship=relationship)
        self.__entity = entity
        self.__name = name
        # Add the rel="self" link.
        self.add_link(Link(self, "self"))
Beispiel #21
0
 def visit_member(self,
                  attribute_key,
                  attribute,
                  member_node,
                  member_data,
                  is_link_node,
                  parent_data,
                  index=None):
     if is_link_node:
         url = member_node.get_url()
         rc = url_to_resource(url)
         entity = rc.get_entity()
     else:
         entity_cls = get_entity_class(member_node.mapping.mapped_class)
         entity_data = {}
         nested_entity_data = {}
         for attr, value in member_data.iteritems():
             if '.' in attr.entity_name:
                 nested_entity_data[attr.entity_name] = value
             else:
                 entity_data[attr.entity_name] = value
         entity = entity_cls.create_from_data(entity_data)
         # Set nested attribute values.
         # FIXME: lazy loading of nested attributes is not supported.
         for nested_attr, value in nested_entity_data.iteritems():
             tokens = nested_attr.split('.')
             parent = reduce(getattr, tokens[:-1], entity)
             if not parent is None:
                 setattr(parent, tokens[-1], value)
     if not index is None:
         # Collection member. Store in parent data with index as key.
         parent_data[index] = entity
     elif len(attribute_key) == 0:
         # Top level. Store root entity and create resource.
         mapped_cls = member_node.mapping.mapped_class
         self.__resource = mapped_cls.create_from_entity(entity)
     else:
         # Nested member. Store in parent data with attribute as key.
         parent_data[attribute] = entity
Beispiel #22
0
 def _convert_to_entity(self):
     init_map = {}
     nested_map = {}
     mapped_class = self._data.mapping.mapped_class
     for attr in \
         self.__mapping.attribute_iterator(mapped_class=mapped_class,
                                           key=self.__attribute_key):
         try:
             val = self._get_proxied_attribute_value(attr)
         except AttributeError:
             continue
         else:
             attr_name = attr.entity_attr
             if not '.' in attr_name:
                 init_map[attr_name] = val
             else:
                 nested_map[attr_name] = val
     ent_cls = get_entity_class(mapped_class)
     entity = ent_cls.create_from_data(init_map)
     for nested_name, nested_value in iteritems_(nested_map):
         set_nested_attribute(entity, nested_name, nested_value)
     return entity
Beispiel #23
0
 def _convert_to_entity(self):
     init_map = {}
     nested_map = {}
     mapped_class = self._data.mapping.mapped_class
     for attr in \
         self.__mapping.attribute_iterator(mapped_class=mapped_class,
                                           key=self.__attribute_key):
         try:
             val = self._get_proxied_attribute_value(attr)
         except AttributeError:
             continue
         else:
             attr_name = attr.entity_attr
             if not '.' in attr_name:
                 init_map[attr_name] = val
             else:
                 nested_map[attr_name] = val
     ent_cls = get_entity_class(mapped_class)
     entity = ent_cls.create_from_data(init_map)
     for nested_name, nested_value in iteritems_(nested_map):
         set_nested_attribute(entity, nested_name, nested_value)
     return entity
Beispiel #24
0
 def visit(self, path, attribute, source, target):
     is_root = attribute is None
     if is_root:
         # Visiting the root.
         ent_class = get_entity_class(self._rc_class)
     else:
         ent_class = get_entity_class(attribute.attr_type)
         parent = path.parent
     if source is None:
         # No source - REMOVE.
         entity = target.get_entity()
         if not is_root:
             rel = self.__get_relationship(parent, attribute)
             rel.remove(entity)
         if not self.__remove_callback is None:
             if self.__pass_path_to_callbacks:
                 args = (ent_class, entity, path)
             else:
                 args = (ent_class, entity)
             cmd = self.RemoveCallback(self.__remove_callback, args)
             self.__commands.append(cmd)
     else:
         if target is None:
             # No target - ADD.
             entity = source.get_entity()
             if not is_root:
                 if path.relation_operation == RELATION_OPERATIONS.ADD:
                     # If the parent is created new, the constructor
                     # will most likely set the child attribute.
                     add_opts = dict(safe=True)
                 else:
                     add_opts = dict()
                 rel = self.__get_relationship(parent, attribute)
                 rel.add(entity, **add_opts)
             if not self.__add_callback is None:
                 if self.__pass_path_to_callbacks:
                     args = (ent_class, entity, path)
                 else:
                     args = (ent_class, entity)
                 cmd = self.AddCallback(self.__add_callback, args)
                 self.__commands.append(cmd)
         else:
             # Both source and target - UPDATE.
             entity = target.get_entity()
             if not self.__update_callback is None:
                 upd_av_map = dict(source.update_attribute_value_items)
                 if self.__pass_path_to_callbacks:
                     args = (ent_class, upd_av_map, entity, path)
                 else:
                     args = (ent_class, upd_av_map, entity)
                 cmd = self.UpdateCallback(self.__update_callback, args)
                 self.__commands.append(cmd)
             if not is_root:
                 # The relationship with the old value has already been
                 # severed, so we only need to ADD here.
                 rel = self.__get_relationship(parent, attribute)
                 rel.add(entity)
     if is_root:
         self.root = entity
     else:
         self.__commands.append(rel)
Beispiel #25
0
 def _get_entity_type(self):
     return get_entity_class(self._data.mapping.mapped_class)
 def test_get_entity_class(self):
     self.assert_true(get_entity_class(IFoo), FooEntity)
Beispiel #27
0
 def _get_entity_type(self):
     return get_entity_class(self._data.mapping.mapped_class)
Beispiel #28
0
 def wrap(ent, *args):
     if isinstance(ent, type) and IEntity in implemented_by(ent):
         ent_cls = ent
     else:
         ent_cls = get_entity_class(ent)
     return func(ent_cls, *args)
Beispiel #29
0
 def get_root_aggregate(self, rc):
     ent_cls = get_entity_class(rc)
     return StagingAggregate(ent_cls, cache=self.__cache_map)
Beispiel #30
0
 def get_root_aggregate(self, rc):
     ent_cls = get_entity_class(rc)
     return StagingAggregate(ent_cls, cache=self.__cache_map)
Beispiel #31
0
 def wrap(ent, *args):
     if isinstance(ent, type) and IEntity in implemented_by(ent):
         ent_cls = ent
     else:
         ent_cls = get_entity_class(ent)
     return func(ent_cls, *args)
Beispiel #32
0
 def test_get_entity_class(self):
     self.assert_true(get_entity_class(IFoo), FooEntity)