497 self.commit() |
503 self.commit() |
498 else: |
504 else: |
499 self.rollback() |
505 self.rollback() |
500 return False #propagate the exception |
506 return False #propagate the exception |
501 |
507 |
502 def _txid(self, cursor=None): # XXX could now handle various isolation level! |
508 def __del__(self): |
503 # return a dict as bw compat trick |
509 """close the remote connection if necessary""" |
504 return {'txid': currentThread().getName()} |
510 if self._closed is None and self._close_on_del: |
505 |
511 try: |
506 def request(self): |
512 self.close() |
507 return DBAPIRequest(self.vreg, DBAPISession(self)) |
513 except: |
508 |
514 pass |
509 def check(self): |
515 |
510 """raise `BadConnectionId` if the connection is no more valid""" |
516 # connection initialization methods ######################################## |
511 if self._closed is not None: |
|
512 raise ProgrammingError('Closed connection') |
|
513 self._repo.check_session(self.sessionid) |
|
514 |
|
515 def set_session_props(self, **props): |
|
516 """raise `BadConnectionId` if the connection is no more valid""" |
|
517 if self._closed is not None: |
|
518 raise ProgrammingError('Closed connection') |
|
519 self._repo.set_session_props(self.sessionid, props) |
|
520 |
|
521 def get_shared_data(self, key, default=None, pop=False): |
|
522 """return value associated to `key` in shared data""" |
|
523 if self._closed is not None: |
|
524 raise ProgrammingError('Closed connection') |
|
525 return self._repo.get_shared_data(self.sessionid, key, default, pop) |
|
526 |
|
527 def set_shared_data(self, key, value, querydata=False): |
|
528 """set value associated to `key` in shared data |
|
529 |
|
530 if `querydata` is true, the value will be added to the repository |
|
531 session's query data which are cleared on commit/rollback of the current |
|
532 transaction, and won't be available through the connexion, only on the |
|
533 repository side. |
|
534 """ |
|
535 if self._closed is not None: |
|
536 raise ProgrammingError('Closed connection') |
|
537 return self._repo.set_shared_data(self.sessionid, key, value, querydata) |
|
538 |
|
539 def get_schema(self): |
|
540 """Return the schema currently used by the repository. |
|
541 |
|
542 This is NOT part of the DB-API. |
|
543 """ |
|
544 if self._closed is not None: |
|
545 raise ProgrammingError('Closed connection') |
|
546 return self._repo.get_schema() |
|
547 |
517 |
548 def load_appobjects(self, cubes=_MARKER, subpath=None, expand=True): |
518 def load_appobjects(self, cubes=_MARKER, subpath=None, expand=True): |
549 config = self.vreg.config |
519 config = self.vreg.config |
550 if cubes is _MARKER: |
520 if cubes is _MARKER: |
551 cubes = self._repo.get_cubes() |
521 cubes = self._repo.get_cubes() |
597 self.vreg.config.set_option('base-url', baseurl) |
567 self.vreg.config.set_option('base-url', baseurl) |
598 # XXX why is this needed? if really needed, could be fetched by a query |
568 # XXX why is this needed? if really needed, could be fetched by a query |
599 if sitetitle is not None: |
569 if sitetitle is not None: |
600 self.vreg['propertydefs']['ui.site-title'] = {'default': sitetitle} |
570 self.vreg['propertydefs']['ui.site-title'] = {'default': sitetitle} |
601 |
571 |
|
572 @check_not_closed |
602 def source_defs(self): |
573 def source_defs(self): |
603 """Return the definition of sources used by the repository. |
574 """Return the definition of sources used by the repository. |
604 |
575 |
605 This is NOT part of the DB-API. |
576 This is NOT part of the DB-API. |
606 """ |
577 """ |
607 if self._closed is not None: |
|
608 raise ProgrammingError('Closed connection') |
|
609 return self._repo.source_defs() |
578 return self._repo.source_defs() |
610 |
579 |
|
580 @check_not_closed |
611 def user(self, req=None, props=None): |
581 def user(self, req=None, props=None): |
612 """return the User object associated to this connection""" |
582 """return the User object associated to this connection""" |
613 # cnx validity is checked by the call to .user_info |
583 # cnx validity is checked by the call to .user_info |
614 if self._closed is not None: |
|
615 raise ProgrammingError('Closed connection') |
|
616 eid, login, groups, properties = self._repo.user_info(self.sessionid, |
584 eid, login, groups, properties = self._repo.user_info(self.sessionid, |
617 props) |
585 props) |
618 if req is None: |
586 if req is None: |
619 req = self.request() |
587 req = self.request() |
620 rset = req.eid_rset(eid, 'CWUser') |
588 rset = req.eid_rset(eid, 'CWUser') |
626 from cubicweb.entity import Entity |
594 from cubicweb.entity import Entity |
627 user = Entity(req, rset, row=0) |
595 user = Entity(req, rset, row=0) |
628 user['login'] = login # cache login |
596 user['login'] = login # cache login |
629 return user |
597 return user |
630 |
598 |
631 def __del__(self): |
599 @check_not_closed |
632 """close the remote connection if necessary""" |
600 def check(self): |
633 if self._closed is None and self._close_on_del: |
601 """raise `BadConnectionId` if the connection is no more valid""" |
634 try: |
602 self._repo.check_session(self.sessionid) |
635 self.close() |
603 |
636 except: |
604 def _txid(self, cursor=None): # XXX could now handle various isolation level! |
637 pass |
605 # return a dict as bw compat trick |
638 |
606 return {'txid': currentThread().getName()} |
|
607 |
|
608 def request(self): |
|
609 return DBAPIRequest(self.vreg, DBAPISession(self)) |
|
610 |
|
611 # session data methods ##################################################### |
|
612 |
|
613 @check_not_closed |
|
614 def set_session_props(self, **props): |
|
615 """raise `BadConnectionId` if the connection is no more valid""" |
|
616 self._repo.set_session_props(self.sessionid, props) |
|
617 |
|
618 @check_not_closed |
|
619 def get_shared_data(self, key, default=None, pop=False): |
|
620 """return value associated to `key` in shared data""" |
|
621 return self._repo.get_shared_data(self.sessionid, key, default, pop) |
|
622 |
|
623 @check_not_closed |
|
624 def set_shared_data(self, key, value, querydata=False): |
|
625 """set value associated to `key` in shared data |
|
626 |
|
627 if `querydata` is true, the value will be added to the repository |
|
628 session's query data which are cleared on commit/rollback of the current |
|
629 transaction, and won't be available through the connexion, only on the |
|
630 repository side. |
|
631 """ |
|
632 return self._repo.set_shared_data(self.sessionid, key, value, querydata) |
|
633 |
|
634 # meta-data accessors ###################################################### |
|
635 |
|
636 @check_not_closed |
|
637 def get_schema(self): |
|
638 """Return the schema currently used by the repository.""" |
|
639 return self._repo.get_schema() |
|
640 |
|
641 @check_not_closed |
639 def describe(self, eid): |
642 def describe(self, eid): |
640 if self._closed is not None: |
|
641 raise ProgrammingError('Closed connection') |
|
642 return self._repo.describe(self.sessionid, eid, **self._txid()) |
643 return self._repo.describe(self.sessionid, eid, **self._txid()) |
643 |
644 |
|
645 # db-api like interface #################################################### |
|
646 |
|
647 @check_not_closed |
|
648 def commit(self): |
|
649 """Commit pending transaction for this connection to the repository. |
|
650 |
|
651 may raises `Unauthorized` or `ValidationError` if we attempted to do |
|
652 something we're not allowed to for security or integrity reason. |
|
653 |
|
654 If the transaction is undoable, a transaction id will be returned. |
|
655 """ |
|
656 return self._repo.commit(self.sessionid, **self._txid()) |
|
657 |
|
658 @check_not_closed |
|
659 def rollback(self): |
|
660 """This method is optional since not all databases provide transaction |
|
661 support. |
|
662 |
|
663 In case a database does provide transactions this method causes the the |
|
664 database to roll back to the start of any pending transaction. Closing |
|
665 a connection without committing the changes first will cause an implicit |
|
666 rollback to be performed. |
|
667 """ |
|
668 self._repo.rollback(self.sessionid, **self._txid()) |
|
669 |
|
670 @check_not_closed |
|
671 def cursor(self, req=None): |
|
672 """Return a new Cursor Object using the connection. |
|
673 |
|
674 On pyro connection, you should get cursor after calling if |
|
675 load_appobjects method if desired (which you should call if you intend |
|
676 to use ORM abilities). |
|
677 """ |
|
678 if req is None: |
|
679 req = self.request() |
|
680 return self.cursor_class(self, self._repo, req=req) |
|
681 |
|
682 @check_not_closed |
644 def close(self): |
683 def close(self): |
645 """Close the connection now (rather than whenever __del__ is called). |
684 """Close the connection now (rather than whenever __del__ is called). |
646 |
685 |
647 The connection will be unusable from this point forward; an Error (or |
686 The connection will be unusable from this point forward; an Error (or |
648 subclass) exception will be raised if any operation is attempted with |
687 subclass) exception will be raised if any operation is attempted with |
649 the connection. The same applies to all cursor objects trying to use the |
688 the connection. The same applies to all cursor objects trying to use the |
650 connection. Note that closing a connection without committing the |
689 connection. Note that closing a connection without committing the |
651 changes first will cause an implicit rollback to be performed. |
690 changes first will cause an implicit rollback to be performed. |
652 """ |
691 """ |
653 if self._closed: |
|
654 raise ProgrammingError('Connection is already closed') |
|
655 self._repo.close(self.sessionid, **self._txid()) |
692 self._repo.close(self.sessionid, **self._txid()) |
656 del self._repo # necessary for proper garbage collection |
693 del self._repo # necessary for proper garbage collection |
657 self._closed = 1 |
694 self._closed = 1 |
658 |
695 |
659 def commit(self): |
|
660 """Commit pending transaction for this connection to the repository. |
|
661 |
|
662 may raises `Unauthorized` or `ValidationError` if we attempted to do |
|
663 something we're not allowed to for security or integrity reason. |
|
664 |
|
665 If the transaction is undoable, a transaction id will be returned. |
|
666 """ |
|
667 if not self._closed is None: |
|
668 raise ProgrammingError('Connection is already closed') |
|
669 return self._repo.commit(self.sessionid, **self._txid()) |
|
670 |
|
671 def rollback(self): |
|
672 """This method is optional since not all databases provide transaction |
|
673 support. |
|
674 |
|
675 In case a database does provide transactions this method causes the the |
|
676 database to roll back to the start of any pending transaction. Closing |
|
677 a connection without committing the changes first will cause an implicit |
|
678 rollback to be performed. |
|
679 """ |
|
680 if not self._closed is None: |
|
681 raise ProgrammingError('Connection is already closed') |
|
682 self._repo.rollback(self.sessionid, **self._txid()) |
|
683 |
|
684 def cursor(self, req=None): |
|
685 """Return a new Cursor Object using the connection. |
|
686 |
|
687 On pyro connection, you should get cursor after calling if |
|
688 load_appobjects method if desired (which you should call if you intend |
|
689 to use ORM abilities). |
|
690 """ |
|
691 if self._closed is not None: |
|
692 raise ProgrammingError('Can\'t get cursor on closed connection') |
|
693 if req is None: |
|
694 req = self.request() |
|
695 return self.cursor_class(self, self._repo, req=req) |
|
696 |
|
697 # undo support ############################################################ |
696 # undo support ############################################################ |
698 |
697 |
|
698 @check_not_closed |
699 def undoable_transactions(self, ueid=None, req=None, **actionfilters): |
699 def undoable_transactions(self, ueid=None, req=None, **actionfilters): |
700 """Return a list of undoable transaction objects by the connection's |
700 """Return a list of undoable transaction objects by the connection's |
701 user, ordered by descendant transaction time. |
701 user, ordered by descendant transaction time. |
702 |
702 |
703 Managers may filter according to user (eid) who has done the transaction |
703 Managers may filter according to user (eid) who has done the transaction |