31 |
31 |
32 from yams import BadSchemaDefinition |
32 from yams import BadSchemaDefinition |
33 from yams.schema import role_name |
33 from yams.schema import role_name |
34 from rql import RQLSyntaxError |
34 from rql import RQLSyntaxError |
35 |
35 |
36 from cubicweb import (CW_SOFTWARE_ROOT, CW_MIGRATION_MAP, |
36 from cubicweb import (CW_SOFTWARE_ROOT, CW_MIGRATION_MAP, QueryError, |
37 UnknownEid, AuthenticationError, ExecutionError, |
37 UnknownEid, AuthenticationError, ExecutionError, |
38 ETypeNotSupportedBySources, MultiSourcesError, |
38 ETypeNotSupportedBySources, MultiSourcesError, |
39 BadConnectionId, Unauthorized, ValidationError, |
39 BadConnectionId, Unauthorized, ValidationError, |
40 RepositoryError, typed_eid, onevent) |
40 RepositoryError, typed_eid, onevent) |
41 from cubicweb import cwvreg, schema, server |
41 from cubicweb import cwvreg, schema, server |
74 if card[0] in '1?': |
74 if card[0] in '1?': |
75 if not rschema.inlined: # inlined relations will be implicitly deleted |
75 if not rschema.inlined: # inlined relations will be implicitly deleted |
76 with security_enabled(session, read=False): |
76 with security_enabled(session, read=False): |
77 session.execute('DELETE X %s Y WHERE X eid %%(x)s, ' |
77 session.execute('DELETE X %s Y WHERE X eid %%(x)s, ' |
78 'NOT Y eid %%(y)s' % rtype, |
78 'NOT Y eid %%(y)s' % rtype, |
79 {'x': eidfrom, 'y': eidto}, 'x') |
79 {'x': eidfrom, 'y': eidto}) |
80 if card[1] in '1?': |
80 if card[1] in '1?': |
81 with security_enabled(session, read=False): |
81 with security_enabled(session, read=False): |
82 session.execute('DELETE X %sY WHERE Y eid %%(y)s, ' |
82 session.execute('DELETE X %sY WHERE Y eid %%(y)s, ' |
83 'NOT X eid %%(x)s' % rtype, |
83 'NOT X eid %%(x)s' % rtype, |
84 {'x': eidfrom, 'y': eidto}, 'y') |
84 {'x': eidfrom, 'y': eidto}) |
85 |
85 |
86 |
86 |
87 class Repository(object): |
87 class Repository(object): |
88 """a repository provides access to a set of persistent storages for |
88 """a repository provides access to a set of persistent storages for |
89 entities and relations |
89 entities and relations |
406 |
406 |
407 def _build_user(self, session, eid): |
407 def _build_user(self, session, eid): |
408 """return a CWUser entity for user with the given eid""" |
408 """return a CWUser entity for user with the given eid""" |
409 cls = self.vreg['etypes'].etype_class('CWUser') |
409 cls = self.vreg['etypes'].etype_class('CWUser') |
410 rql = cls.fetch_rql(session.user, ['X eid %(x)s']) |
410 rql = cls.fetch_rql(session.user, ['X eid %(x)s']) |
411 rset = session.execute(rql, {'x': eid}, 'x') |
411 rset = session.execute(rql, {'x': eid}) |
412 assert len(rset) == 1, rset |
412 assert len(rset) == 1, rset |
413 cwuser = rset.get_entity(0, 0) |
413 cwuser = rset.get_entity(0, 0) |
414 # pylint: disable-msg=W0104 |
414 # pylint: disable-msg=W0104 |
415 # prefetch / cache cwuser's groups and properties. This is especially |
415 # prefetch / cache cwuser's groups and properties. This is especially |
416 # useful for internal sessions to avoid security insertions |
416 # useful for internal sessions to avoid security insertions |
565 # commit session at this point in case write operation has been done |
565 # commit session at this point in case write operation has been done |
566 # during `session_open` hooks |
566 # during `session_open` hooks |
567 session.commit() |
567 session.commit() |
568 return session.id |
568 return session.id |
569 |
569 |
570 def execute(self, sessionid, rqlstring, args=None, eid_key=None, build_descr=True): |
570 def execute(self, sessionid, rqlstring, args=None, build_descr=True): |
571 """execute a RQL query |
571 """execute a RQL query |
572 |
572 |
573 * rqlstring should be an unicode string or a plain ascii string |
573 * rqlstring should be an unicode string or a plain ascii string |
574 * args the optional parameters used in the query |
574 * args the optional parameters used in the query |
575 * build_descr is a flag indicating if the description should be |
575 * build_descr is a flag indicating if the description should be |
576 built on select queries |
576 built on select queries |
577 """ |
577 """ |
578 session = self._get_session(sessionid, setpool=True) |
578 session = self._get_session(sessionid, setpool=True) |
579 try: |
579 try: |
580 try: |
580 try: |
581 return self.querier.execute(session, rqlstring, args, eid_key, |
581 return self.querier.execute(session, rqlstring, args, |
582 build_descr) |
582 build_descr) |
583 except (Unauthorized, RQLSyntaxError): |
583 except (Unauthorized, RQLSyntaxError): |
584 raise |
584 raise |
585 except ValidationError, ex: |
585 except ValidationError, ex: |
586 # need ValidationError normalization here so error may pass |
586 # need ValidationError normalization here so error may pass |
833 return self.type_and_source_from_eid(eid, session)[0] |
833 return self.type_and_source_from_eid(eid, session)[0] |
834 |
834 |
835 def source_from_eid(self, eid, session=None): |
835 def source_from_eid(self, eid, session=None): |
836 """return the source for the given entity's eid""" |
836 """return the source for the given entity's eid""" |
837 return self.sources_by_uri[self.type_and_source_from_eid(eid, session)[1]] |
837 return self.sources_by_uri[self.type_and_source_from_eid(eid, session)[1]] |
|
838 |
|
839 def querier_cache_key(self, session, rql, args, eidkeys): |
|
840 cachekey = [rql] |
|
841 for key in sorted(eidkeys): |
|
842 try: |
|
843 etype = self.type_from_eid(args[key], session) |
|
844 except KeyError: |
|
845 raise QueryError('bad cache key %s (no value)' % key) |
|
846 except TypeError: |
|
847 raise QueryError('bad cache key %s (value: %r)' % ( |
|
848 key, args[key])) |
|
849 cachekey.append(etype) |
|
850 # ensure eid is correctly typed in args |
|
851 args[key] = typed_eid(args[key]) |
|
852 return tuple(cachekey) |
838 |
853 |
839 def eid2extid(self, source, eid, session=None): |
854 def eid2extid(self, source, eid, session=None): |
840 """get local id from an eid""" |
855 """get local id from an eid""" |
841 etype, uri, extid = self.type_and_source_from_eid(eid, session) |
856 etype, uri, extid = self.type_and_source_from_eid(eid, session) |
842 if source.uri != uri: |
857 if source.uri != uri: |
899 if source.should_call_hooks: |
914 if source.should_call_hooks: |
900 self.hm.call_hooks('after_add_entity', session, entity=entity) |
915 self.hm.call_hooks('after_add_entity', session, entity=entity) |
901 else: |
916 else: |
902 # minimal meta-data |
917 # minimal meta-data |
903 session.execute('SET X is E WHERE X eid %(x)s, E name %(name)s', |
918 session.execute('SET X is E WHERE X eid %(x)s, E name %(name)s', |
904 {'x': entity.eid, 'name': entity.__regid__}, 'x') |
919 {'x': entity.eid, 'name': entity.__regid__}) |
905 session.commit(reset_pool) |
920 session.commit(reset_pool) |
906 return eid |
921 return eid |
907 except: |
922 except: |
908 session.rollback(reset_pool) |
923 session.rollback(reset_pool) |
909 raise |
924 raise |
947 # don't skip inlined relation so they are regularly |
962 # don't skip inlined relation so they are regularly |
948 # deleted and so hooks are correctly called |
963 # deleted and so hooks are correctly called |
949 rql = 'DELETE X %s Y WHERE X eid %%(x)s' % rtype |
964 rql = 'DELETE X %s Y WHERE X eid %%(x)s' % rtype |
950 else: |
965 else: |
951 rql = 'DELETE Y %s X WHERE X eid %%(x)s' % rtype |
966 rql = 'DELETE Y %s X WHERE X eid %%(x)s' % rtype |
952 session.execute(rql, {'x': eid}, 'x', build_descr=False) |
967 session.execute(rql, {'x': eid}, build_descr=False) |
953 self.system_source.delete_info(session, entity, sourceuri, extid) |
968 self.system_source.delete_info(session, entity, sourceuri, extid) |
954 |
969 |
955 def locate_relation_source(self, session, subject, rtype, object): |
970 def locate_relation_source(self, session, subject, rtype, object): |
956 subjsource = self.source_from_eid(subject, session) |
971 subjsource = self.source_from_eid(subject, session) |
957 objsource = self.source_from_eid(object, session) |
972 objsource = self.source_from_eid(object, session) |