498 # object (inlined relation) or inserting some inconsistency |
498 # object (inlined relation) or inserting some inconsistency |
499 if rdef.cardinality[1] in '?1': |
499 if rdef.cardinality[1] in '?1': |
500 continue |
500 continue |
501 rql = 'SET X %s V WHERE X eid %%(x)s, Y eid %%(y)s, Y %s V' % ( |
501 rql = 'SET X %s V WHERE X eid %%(x)s, Y eid %%(y)s, Y %s V' % ( |
502 rschema.type, rschema.type) |
502 rschema.type, rschema.type) |
503 execute(rql, {'x': self.eid, 'y': ceid}, ('x', 'y')) |
503 execute(rql, {'x': self.eid, 'y': ceid}) |
504 self.clear_related_cache(rschema.type, 'subject') |
504 self.clear_related_cache(rschema.type, 'subject') |
505 for rschema in self.e_schema.object_relations(): |
505 for rschema in self.e_schema.object_relations(): |
506 if rschema.meta: |
506 if rschema.meta: |
507 continue |
507 continue |
508 # skip already defined relations |
508 # skip already defined relations |
516 # object (inlined relation) or inserting some inconsistency |
516 # object (inlined relation) or inserting some inconsistency |
517 if rdef.cardinality[0] in '?1': |
517 if rdef.cardinality[0] in '?1': |
518 continue |
518 continue |
519 rql = 'SET V %s X WHERE X eid %%(x)s, Y eid %%(y)s, V %s Y' % ( |
519 rql = 'SET V %s X WHERE X eid %%(x)s, Y eid %%(y)s, V %s Y' % ( |
520 rschema.type, rschema.type) |
520 rschema.type, rschema.type) |
521 execute(rql, {'x': self.eid, 'y': ceid}, ('x', 'y')) |
521 execute(rql, {'x': self.eid, 'y': ceid}) |
522 self.clear_related_cache(rschema.type, 'object') |
522 self.clear_related_cache(rschema.type, 'object') |
523 |
523 |
524 # data fetching methods ################################################### |
524 # data fetching methods ################################################### |
525 |
525 |
526 @cached |
526 @cached |
618 if selected: |
618 if selected: |
619 # select V, we need it as the left most selected variable |
619 # select V, we need it as the left most selected variable |
620 # if some outer join are included to fetch inlined relations |
620 # if some outer join are included to fetch inlined relations |
621 rql = 'Any %s,%s %s' % (V, ','.join(var for attr, var in selected), |
621 rql = 'Any %s,%s %s' % (V, ','.join(var for attr, var in selected), |
622 ','.join(rql)) |
622 ','.join(rql)) |
623 rset = self._cw.execute(rql, {'x': self.eid}, 'x', |
623 rset = self._cw.execute(rql, {'x': self.eid}, build_descr=False)[0] |
624 build_descr=False)[0] |
|
625 # handle attributes |
624 # handle attributes |
626 for i in xrange(1, lastattr): |
625 for i in xrange(1, lastattr): |
627 self[str(selected[i-1][0])] = rset[i] |
626 self[str(selected[i-1][0])] = rset[i] |
628 # handle relations |
627 # handle relations |
629 for i in xrange(lastattr, len(rset)): |
628 for i in xrange(lastattr, len(rset)): |
648 except KeyError: |
647 except KeyError: |
649 if not self.is_saved(): |
648 if not self.is_saved(): |
650 return None |
649 return None |
651 rql = "Any A WHERE X eid %%(x)s, X %s A" % name |
650 rql = "Any A WHERE X eid %%(x)s, X %s A" % name |
652 try: |
651 try: |
653 rset = self._cw.execute(rql, {'x': self.eid}, 'x') |
652 rset = self._cw.execute(rql, {'x': self.eid}) |
654 except Unauthorized: |
653 except Unauthorized: |
655 self[name] = value = None |
654 self[name] = value = None |
656 else: |
655 else: |
657 assert rset.rowcount <= 1, (self, rql, rset.rowcount) |
656 assert rset.rowcount <= 1, (self, rql, rset.rowcount) |
658 try: |
657 try: |
679 return self.related_cache(rtype, role, entities, limit) |
678 return self.related_cache(rtype, role, entities, limit) |
680 except KeyError: |
679 except KeyError: |
681 pass |
680 pass |
682 assert self.has_eid() |
681 assert self.has_eid() |
683 rql = self.related_rql(rtype, role) |
682 rql = self.related_rql(rtype, role) |
684 rset = self._cw.execute(rql, {'x': self.eid}, 'x') |
683 rset = self._cw.execute(rql, {'x': self.eid}) |
685 self.set_related_cache(rtype, role, rset) |
684 self.set_related_cache(rtype, role, rset) |
686 return self.related(rtype, role, limit, entities) |
685 return self.related(rtype, role, limit, entities) |
687 |
686 |
688 def related_rql(self, rtype, role='subject', targettypes=None): |
687 def related_rql(self, rtype, role='subject', targettypes=None): |
689 rschema = self._cw.vreg.schema[rtype] |
688 rschema = self._cw.vreg.schema[rtype] |
805 except Unauthorized: |
804 except Unauthorized: |
806 return self._cw.empty_rset() |
805 return self._cw.empty_rset() |
807 if limit is not None: |
806 if limit is not None: |
808 before, after = rql.split(' WHERE ', 1) |
807 before, after = rql.split(' WHERE ', 1) |
809 rql = '%s LIMIT %s WHERE %s' % (before, limit, after) |
808 rql = '%s LIMIT %s WHERE %s' % (before, limit, after) |
810 return self._cw.execute(rql, args, tuple(args)) |
809 return self._cw.execute(rql, args) |
811 |
810 |
812 # relations cache handling ################################################ |
811 # relations cache handling ################################################ |
813 |
812 |
814 def relation_cached(self, rtype, role): |
813 def relation_cached(self, rtype, role): |
815 """return true if the given relation is already cached on the instance |
814 """return true if the given relation is already cached on the instance |
888 for key in kwargs: |
887 for key in kwargs: |
889 relations.append('X %s %%(%s)s' % (key, key)) |
888 relations.append('X %s %%(%s)s' % (key, key)) |
890 # and now update the database |
889 # and now update the database |
891 kwargs['x'] = self.eid |
890 kwargs['x'] = self.eid |
892 self._cw.execute('SET %s WHERE X eid %%(x)s' % ','.join(relations), |
891 self._cw.execute('SET %s WHERE X eid %%(x)s' % ','.join(relations), |
893 kwargs, 'x') |
892 kwargs) |
894 kwargs.pop('x') |
893 kwargs.pop('x') |
895 # update current local object _after_ the rql query to avoid |
894 # update current local object _after_ the rql query to avoid |
896 # interferences between the query execution itself and the |
895 # interferences between the query execution itself and the |
897 # edited_attributes / skip_security_attributes machinery |
896 # edited_attributes / skip_security_attributes machinery |
898 self.update(kwargs) |
897 self.update(kwargs) |
911 restr = 'Y %s X' % attr[len('reverse_'):] |
910 restr = 'Y %s X' % attr[len('reverse_'):] |
912 else: |
911 else: |
913 restr = 'X %s Y' % attr |
912 restr = 'X %s Y' % attr |
914 if values is None: |
913 if values is None: |
915 self._cw.execute('DELETE %s WHERE X eid %%(x)s' % restr, |
914 self._cw.execute('DELETE %s WHERE X eid %%(x)s' % restr, |
916 {'x': self.eid}, 'x') |
915 {'x': self.eid}) |
917 continue |
916 continue |
918 if not isinstance(values, (tuple, list, set, frozenset)): |
917 if not isinstance(values, (tuple, list, set, frozenset)): |
919 values = (values,) |
918 values = (values,) |
920 self._cw.execute('SET %s WHERE X eid %%(x)s, Y eid IN (%s)' % ( |
919 self._cw.execute('SET %s WHERE X eid %%(x)s, Y eid IN (%s)' % ( |
921 restr, ','.join(str(r.eid) for r in values)), |
920 restr, ','.join(str(r.eid) for r in values)), |
922 {'x': self.eid}, 'x') |
921 {'x': self.eid}) |
923 |
922 |
924 def delete(self, **kwargs): |
923 def delete(self, **kwargs): |
925 assert self.has_eid(), self.eid |
924 assert self.has_eid(), self.eid |
926 self._cw.execute('DELETE %s X WHERE X eid %%(x)s' % self.e_schema, |
925 self._cw.execute('DELETE %s X WHERE X eid %%(x)s' % self.e_schema, |
927 {'x': self.eid}, **kwargs) |
926 {'x': self.eid}, **kwargs) |