572 # object (inlined relation) or inserting some inconsistency |
572 # object (inlined relation) or inserting some inconsistency |
573 if rdef.cardinality[1] in '?1': |
573 if rdef.cardinality[1] in '?1': |
574 continue |
574 continue |
575 rql = 'SET X %s V WHERE X eid %%(x)s, Y eid %%(y)s, Y %s V' % ( |
575 rql = 'SET X %s V WHERE X eid %%(x)s, Y eid %%(y)s, Y %s V' % ( |
576 rschema.type, rschema.type) |
576 rschema.type, rschema.type) |
577 execute(rql, {'x': self.eid, 'y': ceid}, ('x', 'y')) |
577 execute(rql, {'x': self.eid, 'y': ceid}) |
578 self.clear_related_cache(rschema.type, 'subject') |
578 self.clear_related_cache(rschema.type, 'subject') |
579 for rschema in self.e_schema.object_relations(): |
579 for rschema in self.e_schema.object_relations(): |
580 if rschema.meta: |
580 if rschema.meta: |
581 continue |
581 continue |
582 # skip already defined relations |
582 # skip already defined relations |
590 # object (inlined relation) or inserting some inconsistency |
590 # object (inlined relation) or inserting some inconsistency |
591 if rdef.cardinality[0] in '?1': |
591 if rdef.cardinality[0] in '?1': |
592 continue |
592 continue |
593 rql = 'SET V %s X WHERE X eid %%(x)s, Y eid %%(y)s, V %s Y' % ( |
593 rql = 'SET V %s X WHERE X eid %%(x)s, Y eid %%(y)s, V %s Y' % ( |
594 rschema.type, rschema.type) |
594 rschema.type, rschema.type) |
595 execute(rql, {'x': self.eid, 'y': ceid}, ('x', 'y')) |
595 execute(rql, {'x': self.eid, 'y': ceid}) |
596 self.clear_related_cache(rschema.type, 'object') |
596 self.clear_related_cache(rschema.type, 'object') |
597 |
597 |
598 # data fetching methods ################################################### |
598 # data fetching methods ################################################### |
599 |
599 |
600 @cached |
600 @cached |
692 if selected: |
692 if selected: |
693 # select V, we need it as the left most selected variable |
693 # select V, we need it as the left most selected variable |
694 # if some outer join are included to fetch inlined relations |
694 # if some outer join are included to fetch inlined relations |
695 rql = 'Any %s,%s %s' % (V, ','.join(var for attr, var in selected), |
695 rql = 'Any %s,%s %s' % (V, ','.join(var for attr, var in selected), |
696 ','.join(rql)) |
696 ','.join(rql)) |
697 rset = self._cw.execute(rql, {'x': self.eid}, 'x', |
697 rset = self._cw.execute(rql, {'x': self.eid}, build_descr=False)[0] |
698 build_descr=False)[0] |
|
699 # handle attributes |
698 # handle attributes |
700 for i in xrange(1, lastattr): |
699 for i in xrange(1, lastattr): |
701 self[str(selected[i-1][0])] = rset[i] |
700 self[str(selected[i-1][0])] = rset[i] |
702 # handle relations |
701 # handle relations |
703 for i in xrange(lastattr, len(rset)): |
702 for i in xrange(lastattr, len(rset)): |
722 except KeyError: |
721 except KeyError: |
723 if not self.is_saved(): |
722 if not self.is_saved(): |
724 return None |
723 return None |
725 rql = "Any A WHERE X eid %%(x)s, X %s A" % name |
724 rql = "Any A WHERE X eid %%(x)s, X %s A" % name |
726 try: |
725 try: |
727 rset = self._cw.execute(rql, {'x': self.eid}, 'x') |
726 rset = self._cw.execute(rql, {'x': self.eid}) |
728 except Unauthorized: |
727 except Unauthorized: |
729 self[name] = value = None |
728 self[name] = value = None |
730 else: |
729 else: |
731 assert rset.rowcount <= 1, (self, rql, rset.rowcount) |
730 assert rset.rowcount <= 1, (self, rql, rset.rowcount) |
732 try: |
731 try: |
753 return self.related_cache(rtype, role, entities, limit) |
752 return self.related_cache(rtype, role, entities, limit) |
754 except KeyError: |
753 except KeyError: |
755 pass |
754 pass |
756 assert self.has_eid() |
755 assert self.has_eid() |
757 rql = self.related_rql(rtype, role) |
756 rql = self.related_rql(rtype, role) |
758 rset = self._cw.execute(rql, {'x': self.eid}, 'x') |
757 rset = self._cw.execute(rql, {'x': self.eid}) |
759 self.set_related_cache(rtype, role, rset) |
758 self.set_related_cache(rtype, role, rset) |
760 return self.related(rtype, role, limit, entities) |
759 return self.related(rtype, role, limit, entities) |
761 |
760 |
762 def related_rql(self, rtype, role='subject', targettypes=None): |
761 def related_rql(self, rtype, role='subject', targettypes=None): |
763 rschema = self._cw.vreg.schema[rtype] |
762 rschema = self._cw.vreg.schema[rtype] |
879 except Unauthorized: |
878 except Unauthorized: |
880 return self._cw.empty_rset() |
879 return self._cw.empty_rset() |
881 if limit is not None: |
880 if limit is not None: |
882 before, after = rql.split(' WHERE ', 1) |
881 before, after = rql.split(' WHERE ', 1) |
883 rql = '%s LIMIT %s WHERE %s' % (before, limit, after) |
882 rql = '%s LIMIT %s WHERE %s' % (before, limit, after) |
884 return self._cw.execute(rql, args, tuple(args)) |
883 return self._cw.execute(rql, args) |
885 |
884 |
886 # relations cache handling ################################################ |
885 # relations cache handling ################################################ |
887 |
886 |
888 def relation_cached(self, rtype, role): |
887 def relation_cached(self, rtype, role): |
889 """return true if the given relation is already cached on the instance |
888 """return true if the given relation is already cached on the instance |
962 for key in kwargs: |
961 for key in kwargs: |
963 relations.append('X %s %%(%s)s' % (key, key)) |
962 relations.append('X %s %%(%s)s' % (key, key)) |
964 # and now update the database |
963 # and now update the database |
965 kwargs['x'] = self.eid |
964 kwargs['x'] = self.eid |
966 self._cw.execute('SET %s WHERE X eid %%(x)s' % ','.join(relations), |
965 self._cw.execute('SET %s WHERE X eid %%(x)s' % ','.join(relations), |
967 kwargs, 'x') |
966 kwargs) |
968 kwargs.pop('x') |
967 kwargs.pop('x') |
969 # update current local object _after_ the rql query to avoid |
968 # update current local object _after_ the rql query to avoid |
970 # interferences between the query execution itself and the |
969 # interferences between the query execution itself and the |
971 # edited_attributes / skip_security_attributes machinery |
970 # edited_attributes / skip_security_attributes machinery |
972 self.update(kwargs) |
971 self.update(kwargs) |
985 restr = 'Y %s X' % attr[len('reverse_'):] |
984 restr = 'Y %s X' % attr[len('reverse_'):] |
986 else: |
985 else: |
987 restr = 'X %s Y' % attr |
986 restr = 'X %s Y' % attr |
988 if values is None: |
987 if values is None: |
989 self._cw.execute('DELETE %s WHERE X eid %%(x)s' % restr, |
988 self._cw.execute('DELETE %s WHERE X eid %%(x)s' % restr, |
990 {'x': self.eid}, 'x') |
989 {'x': self.eid}) |
991 continue |
990 continue |
992 if not isinstance(values, (tuple, list, set, frozenset)): |
991 if not isinstance(values, (tuple, list, set, frozenset)): |
993 values = (values,) |
992 values = (values,) |
994 self._cw.execute('SET %s WHERE X eid %%(x)s, Y eid IN (%s)' % ( |
993 self._cw.execute('SET %s WHERE X eid %%(x)s, Y eid IN (%s)' % ( |
995 restr, ','.join(str(r.eid) for r in values)), |
994 restr, ','.join(str(r.eid) for r in values)), |
996 {'x': self.eid}, 'x') |
995 {'x': self.eid}) |
997 |
996 |
998 def delete(self, **kwargs): |
997 def delete(self, **kwargs): |
999 assert self.has_eid(), self.eid |
998 assert self.has_eid(), self.eid |
1000 self._cw.execute('DELETE %s X WHERE X eid %%(x)s' % self.e_schema, |
999 self._cw.execute('DELETE %s X WHERE X eid %%(x)s' % self.e_schema, |
1001 {'x': self.eid}, **kwargs) |
1000 {'x': self.eid}, **kwargs) |