entity.py
changeset 7798 8930f7a284dd
parent 7794 aed065b97f12
child 7803 02e141e41da2
equal deleted inserted replaced
7797:a71618a75b53 7798:8930f7a284dd
    61     # the check for ?, /, & are to prevent problems when running
    61     # the check for ?, /, & are to prevent problems when running
    62     # behind Apache mod_proxy
    62     # behind Apache mod_proxy
    63     if value == u'' or u'?' in value or u'/' in value or u'&' in value:
    63     if value == u'' or u'?' in value or u'/' in value or u'&' in value:
    64         return False
    64         return False
    65     return True
    65     return True
    66 
       
    67 
       
    68 def remove_ambiguous_rels(attr_set, subjtypes, schema):
       
    69     '''remove from `attr_set` the relations of entity types `subjtypes` that have
       
    70     different entity type sets as target'''
       
    71     for attr in attr_set.copy():
       
    72         rschema = schema.rschema(attr)
       
    73         if rschema.final:
       
    74             continue
       
    75         ttypes = None
       
    76         for subjtype in subjtypes:
       
    77             cur_ttypes = rschema.objects(subjtype)
       
    78             if ttypes is None:
       
    79                 ttypes = cur_ttypes
       
    80             elif cur_ttypes != ttypes:
       
    81                 attr_set.remove(attr)
       
    82                 break
       
    83 
    66 
    84 
    67 
    85 class Entity(AppObject):
    68 class Entity(AppObject):
    86     """an entity instance has e_schema automagically set on
    69     """an entity instance has e_schema automagically set on
    87     the class and instances has access to their issuing cursor.
    70     the class and instances has access to their issuing cursor.
   213             fetchattrs = cls.fetch_attrs
   196             fetchattrs = cls.fetch_attrs
   214         cls._fetch_restrictions(mainvar, select, fetchattrs, user, ordermethod)
   197         cls._fetch_restrictions(mainvar, select, fetchattrs, user, ordermethod)
   215         return select
   198         return select
   216 
   199 
   217     @classmethod
   200     @classmethod
       
   201     def _fetch_ambiguous_rtypes(cls, select, var, fetchattrs, subjtypes, schema):
       
   202         """find rtypes in `fetchattrs` that relate different subject etypes
       
   203         taken from (`subjtypes`) to different target etypes; these so called
       
   204         "ambiguous" relations, are added directly to the `select` syntax tree
       
   205         selection but removed from `fetchattrs` to avoid the fetch recursion
       
   206         because we have to choose only one targettype for the recursion and
       
   207         adding its own fetch attrs to the selection -when we recurse- would
       
   208         filter out the other possible target types from the result set
       
   209         """
       
   210         for attr in fetchattrs.copy():
       
   211             rschema = schema.rschema(attr)
       
   212             if rschema.final:
       
   213                 continue
       
   214             ttypes = None
       
   215             for subjtype in subjtypes:
       
   216                 cur_ttypes = set(rschema.objects(subjtype))
       
   217                 if ttypes is None:
       
   218                     ttypes = cur_ttypes
       
   219                 elif cur_ttypes != ttypes:
       
   220                     # we found an ambiguous relation: remove it from fetchattrs
       
   221                     fetchattrs.remove(attr)
       
   222                     # ... and add it to the selection
       
   223                     targetvar = select.make_variable()
       
   224                     select.add_selected(targetvar)
       
   225                     rel = make_relation(var, attr, (targetvar,), VariableRef)
       
   226                     select.add_restriction(rel)
       
   227                     break
       
   228 
       
   229     @classmethod
   218     def _fetch_restrictions(cls, mainvar, select, fetchattrs,
   230     def _fetch_restrictions(cls, mainvar, select, fetchattrs,
   219                             user, ordermethod='fetch_order', visited=None):
   231                             user, ordermethod='fetch_order', visited=None):
   220         eschema = cls.e_schema
   232         eschema = cls.e_schema
   221         if visited is None:
   233         if visited is None:
   222             visited = set((eschema.type,))
   234             visited = set((eschema.type,))
   250                 # (card == '?')  *or if the entity is being added*, since in
   262                 # (card == '?')  *or if the entity is being added*, since in
   251                 # that case the relation may still be missing. As we miss this
   263                 # that case the relation may still be missing. As we miss this
   252                 # later information here, systematically add it.
   264                 # later information here, systematically add it.
   253                 rel.change_optional('right')
   265                 rel.change_optional('right')
   254                 targettypes = rschema.objects(eschema.type)
   266                 targettypes = rschema.objects(eschema.type)
   255                 # XXX user._cw.vreg iiiirk
   267                 vreg = user._cw.vreg # XXX user._cw.vreg iiiirk
   256                 etypecls = user._cw.vreg['etypes'].etype_class(targettypes[0])
   268                 etypecls = vreg['etypes'].etype_class(targettypes[0])
   257                 if len(targettypes) > 1:
   269                 if len(targettypes) > 1:
   258                     # find fetch_attrs common to all destination types
   270                     # find fetch_attrs common to all destination types
   259                     fetchattrs = user._cw.vreg['etypes'].fetch_attrs(targettypes)
   271                     fetchattrs = vreg['etypes'].fetch_attrs(targettypes)
   260                     remove_ambiguous_rels(fetchattrs, targettypes, user._cw.vreg.schema)
   272                     # .. and handle ambiguous relations
       
   273                     cls._fetch_ambiguous_rtypes(select, var, fetchattrs,
       
   274                                                 targettypes, vreg.schema)
   261                 else:
   275                 else:
   262                     fetchattrs = etypecls.fetch_attrs
   276                     fetchattrs = etypecls.fetch_attrs
   263                 etypecls._fetch_restrictions(var, select, fetchattrs,
   277                 etypecls._fetch_restrictions(var, select, fetchattrs,
   264                                              user, ordermethod, visited=visited)
   278                                              user, ordermethod, visited=visited)
   265             if ordermethod is not None:
   279             if ordermethod is not None:
   770         rset = self._cw.execute(rql, {'x': self.eid})
   784         rset = self._cw.execute(rql, {'x': self.eid})
   771         self.cw_set_relation_cache(rtype, role, rset)
   785         self.cw_set_relation_cache(rtype, role, rset)
   772         return self.related(rtype, role, limit, entities)
   786         return self.related(rtype, role, limit, entities)
   773 
   787 
   774     def cw_related_rql(self, rtype, role='subject', targettypes=None):
   788     def cw_related_rql(self, rtype, role='subject', targettypes=None):
   775         rschema = self._cw.vreg.schema[rtype]
   789         vreg = self._cw.vreg
       
   790         rschema = vreg.schema[rtype]
   776         select = Select()
   791         select = Select()
   777         mainvar, evar = select.get_variable('X'), select.get_variable('E')
   792         mainvar, evar = select.get_variable('X'), select.get_variable('E')
   778         select.add_selected(mainvar)
   793         select.add_selected(mainvar)
   779         select.add_eid_restriction(evar, 'x', 'Substitute')
   794         select.add_eid_restriction(evar, 'x', 'Substitute')
   780         if role == 'subject':
   795         if role == 'subject':
   793                 targettypes = rschema.subjects(self.e_schema)
   808                 targettypes = rschema.subjects(self.e_schema)
   794             else:
   809             else:
   795                 select.add_constant_restriction(mainvar, 'is', targettypes,
   810                 select.add_constant_restriction(mainvar, 'is', targettypes,
   796                                                 'String')
   811                                                 'String')
   797             gcard = greater_card(rschema, targettypes, (self.e_schema,), 1)
   812             gcard = greater_card(rschema, targettypes, (self.e_schema,), 1)
   798         etypecls = self._cw.vreg['etypes'].etype_class(targettypes[0])
   813         etypecls = vreg['etypes'].etype_class(targettypes[0])
   799         if len(targettypes) > 1:
   814         if len(targettypes) > 1:
   800             fetchattrs = self._cw.vreg['etypes'].fetch_attrs(targettypes)
   815             fetchattrs = vreg['etypes'].fetch_attrs(targettypes)
   801             # XXX we should fetch ambiguous relation objects too but not
   816             self._fetch_ambiguous_rtypes(select, mainvar, fetchattrs,
   802             # recurse on them in _fetch_restrictions; it is easier to remove
   817                                          targettypes, vreg.schema)
   803             # them completely for now, as it would require a deeper api rewrite
       
   804             remove_ambiguous_rels(fetchattrs, targettypes, self._cw.vreg.schema)
       
   805         else:
   818         else:
   806             fetchattrs = etypecls.fetch_attrs
   819             fetchattrs = etypecls.fetch_attrs
   807         etypecls.fetch_rqlst(self._cw.user, select, mainvar, fetchattrs,
   820         etypecls.fetch_rqlst(self._cw.user, select, mainvar, fetchattrs,
   808                              settype=False)
   821                              settype=False)
   809         # optimisation: remove ORDERBY if cardinality is 1 or ? (though
   822         # optimisation: remove ORDERBY if cardinality is 1 or ? (though