18 |
18 |
19 from cubicweb import Unauthorized, typed_eid |
19 from cubicweb import Unauthorized, typed_eid |
20 from cubicweb.rset import ResultSet |
20 from cubicweb.rset import ResultSet |
21 from cubicweb.selectors import yes |
21 from cubicweb.selectors import yes |
22 from cubicweb.appobject import AppObject |
22 from cubicweb.appobject import AppObject |
|
23 from cubicweb.req import _check_cw_unsafe |
23 from cubicweb.schema import RQLVocabularyConstraint, RQLConstraint |
24 from cubicweb.schema import RQLVocabularyConstraint, RQLConstraint |
24 from cubicweb.rqlrewrite import RQLRewriter |
25 from cubicweb.rqlrewrite import RQLRewriter |
25 |
26 |
26 from cubicweb.uilib import printable_value, soup2xhtml |
27 from cubicweb.uilib import printable_value, soup2xhtml |
27 from cubicweb.mixins import MI_REL_TRIGGERS |
28 from cubicweb.mixins import MI_REL_TRIGGERS |
529 if selected: |
530 if selected: |
530 # select V, we need it as the left most selected variable |
531 # select V, we need it as the left most selected variable |
531 # if some outer join are included to fetch inlined relations |
532 # if some outer join are included to fetch inlined relations |
532 rql = 'Any %s,%s %s' % (V, ','.join(var for attr, var in selected), |
533 rql = 'Any %s,%s %s' % (V, ','.join(var for attr, var in selected), |
533 ','.join(rql)) |
534 ','.join(rql)) |
534 execute = getattr(self._cw, 'unsafe_execute', self._cw.execute) |
535 rset = self._cw.execute(rql, {'x': self.eid}, 'x', |
535 rset = execute(rql, {'x': self.eid}, 'x', build_descr=False)[0] |
536 build_descr=False)[0] |
536 # handle attributes |
537 # handle attributes |
537 for i in xrange(1, lastattr): |
538 for i in xrange(1, lastattr): |
538 self[str(selected[i-1][0])] = rset[i] |
539 self[str(selected[i-1][0])] = rset[i] |
539 # handle relations |
540 # handle relations |
540 for i in xrange(lastattr, len(rset)): |
541 for i in xrange(lastattr, len(rset)): |
558 value = self[name] |
559 value = self[name] |
559 except KeyError: |
560 except KeyError: |
560 if not self.is_saved(): |
561 if not self.is_saved(): |
561 return None |
562 return None |
562 rql = "Any A WHERE X eid %%(x)s, X %s A" % name |
563 rql = "Any A WHERE X eid %%(x)s, X %s A" % name |
563 # XXX should we really use unsafe_execute here? I think so (syt), |
|
564 # see #344874 |
|
565 execute = getattr(self._cw, 'unsafe_execute', self._cw.execute) |
|
566 try: |
564 try: |
567 rset = execute(rql, {'x': self.eid}, 'x') |
565 rset = self._cw.execute(rql, {'x': self.eid}, 'x') |
568 except Unauthorized: |
566 except Unauthorized: |
569 self[name] = value = None |
567 self[name] = value = None |
570 else: |
568 else: |
571 assert rset.rowcount <= 1, (self, rql, rset.rowcount) |
569 assert rset.rowcount <= 1, (self, rql, rset.rowcount) |
572 try: |
570 try: |
593 return self.related_cache(rtype, role, entities, limit) |
591 return self.related_cache(rtype, role, entities, limit) |
594 except KeyError: |
592 except KeyError: |
595 pass |
593 pass |
596 assert self.has_eid() |
594 assert self.has_eid() |
597 rql = self.related_rql(rtype, role) |
595 rql = self.related_rql(rtype, role) |
598 # XXX should we really use unsafe_execute here? I think so (syt), |
596 rset = self._cw.execute(rql, {'x': self.eid}, 'x') |
599 # see #344874 |
|
600 execute = getattr(self._cw, 'unsafe_execute', self._cw.execute) |
|
601 rset = execute(rql, {'x': self.eid}, 'x') |
|
602 self.set_related_cache(rtype, role, rset) |
597 self.set_related_cache(rtype, role, rset) |
603 return self.related(rtype, role, limit, entities) |
598 return self.related(rtype, role, limit, entities) |
604 |
599 |
605 def related_rql(self, rtype, role='subject', targettypes=None): |
600 def related_rql(self, rtype, role='subject', targettypes=None): |
606 rschema = self._cw.vreg.schema[rtype] |
601 rschema = self._cw.vreg.schema[rtype] |
798 except AttributeError: |
793 except AttributeError: |
799 pass |
794 pass |
800 |
795 |
801 # raw edition utilities ################################################### |
796 # raw edition utilities ################################################### |
802 |
797 |
803 def set_attributes(self, _cw_unsafe=False, **kwargs): |
798 def set_attributes(self, **kwargs): |
804 assert kwargs |
799 assert kwargs |
|
800 _check_cw_unsafe(kwargs) |
805 relations = [] |
801 relations = [] |
806 for key in kwargs: |
802 for key in kwargs: |
807 relations.append('X %s %%(%s)s' % (key, key)) |
803 relations.append('X %s %%(%s)s' % (key, key)) |
808 # update current local object |
804 # update current local object |
809 self.update(kwargs) |
805 self.update(kwargs) |
810 # and now update the database |
806 # and now update the database |
811 kwargs['x'] = self.eid |
807 kwargs['x'] = self.eid |
812 if _cw_unsafe: |
808 self._cw.execute('SET %s WHERE X eid %%(x)s' % ','.join(relations), |
813 self._cw.unsafe_execute( |
809 kwargs, 'x') |
814 'SET %s WHERE X eid %%(x)s' % ','.join(relations), kwargs, 'x') |
810 |
815 else: |
811 def set_relations(self, **kwargs): |
816 self._cw.execute('SET %s WHERE X eid %%(x)s' % ','.join(relations), |
|
817 kwargs, 'x') |
|
818 |
|
819 def set_relations(self, _cw_unsafe=False, **kwargs): |
|
820 """add relations to the given object. To set a relation where this entity |
812 """add relations to the given object. To set a relation where this entity |
821 is the object of the relation, use 'reverse_'<relation> as argument name. |
813 is the object of the relation, use 'reverse_'<relation> as argument name. |
822 |
814 |
823 Values may be an entity, a list of entity, or None (meaning that all |
815 Values may be an entity, a list of entity, or None (meaning that all |
824 relations of the given type from or to this object should be deleted). |
816 relations of the given type from or to this object should be deleted). |
825 """ |
817 """ |
826 if _cw_unsafe: |
|
827 execute = self._cw.unsafe_execute |
|
828 else: |
|
829 execute = self._cw.execute |
|
830 # XXX update cache |
818 # XXX update cache |
|
819 _check_cw_unsafe(kwargs) |
831 for attr, values in kwargs.iteritems(): |
820 for attr, values in kwargs.iteritems(): |
832 if attr.startswith('reverse_'): |
821 if attr.startswith('reverse_'): |
833 restr = 'Y %s X' % attr[len('reverse_'):] |
822 restr = 'Y %s X' % attr[len('reverse_'):] |
834 else: |
823 else: |
835 restr = 'X %s Y' % attr |
824 restr = 'X %s Y' % attr |
837 execute('DELETE %s WHERE X eid %%(x)s' % restr, |
826 execute('DELETE %s WHERE X eid %%(x)s' % restr, |
838 {'x': self.eid}, 'x') |
827 {'x': self.eid}, 'x') |
839 continue |
828 continue |
840 if not isinstance(values, (tuple, list, set, frozenset)): |
829 if not isinstance(values, (tuple, list, set, frozenset)): |
841 values = (values,) |
830 values = (values,) |
842 execute('SET %s WHERE X eid %%(x)s, Y eid IN (%s)' % ( |
831 self._cw.execute('SET %s WHERE X eid %%(x)s, Y eid IN (%s)' % ( |
843 restr, ','.join(str(r.eid) for r in values)), |
832 restr, ','.join(str(r.eid) for r in values)), |
844 {'x': self.eid}, 'x') |
833 {'x': self.eid}, 'x') |
845 |
834 |
846 def delete(self): |
835 def delete(self, **kwargs): |
847 assert self.has_eid(), self.eid |
836 assert self.has_eid(), self.eid |
848 self._cw.execute('DELETE %s X WHERE X eid %%(x)s' % self.e_schema, |
837 self._cw.execute('DELETE %s X WHERE X eid %%(x)s' % self.e_schema, |
849 {'x': self.eid}) |
838 {'x': self.eid}, **kwargs) |
850 |
839 |
851 # server side utilities ################################################### |
840 # server side utilities ################################################### |
852 |
841 |
853 def set_defaults(self): |
842 def set_defaults(self): |
854 """set default values according to the schema""" |
843 """set default values according to the schema""" |