[Sqlalchemy-commits] [1265] sqlalchemy/trunk/lib/sqlalchemy: split up Session into Session/LegacySes
Brought to you by:
zzzeek
From: <co...@sq...> - 2006-04-06 23:46:15
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head><style type="text/css"><!-- #msg dl { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; } #msg dt { float: left; width: 6em; font-weight: bold; } #msg dt:after { content:':';} #msg dl, #msg dt, #msg ul, #msg li { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; } #msg dl a { font-weight: bold} #msg dl a:link { color:#fc3; } #msg dl a:active { color:#ff0; } #msg dl a:visited { color:#cc6; } h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; } #msg pre { overflow: auto; background: #ffc; border: 1px #fc0 solid; padding: 6px; } #msg ul, pre { overflow: auto; } #patch { width: 100%; } #patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;} #patch .propset h4, #patch .binary h4 {margin:0;} #patch pre {padding:0;line-height:1.2em;margin:0;} #patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;} #patch .propset .diff, #patch .binary .diff {padding:10px 0;} #patch span {display:block;padding:0 10px;} #patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;} #patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;} #patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;} #patch .lines, .info {color:#888;background:#fff;} --></style> <title>[1265] sqlalchemy/trunk/lib/sqlalchemy: split up Session into Session/LegacySession, added some new constructor args</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1265</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-04-06 18:46:02 -0500 (Thu, 06 Apr 2006)</dd> </dl> <h3>Log Message</h3> <pre>split up Session into Session/LegacySession, added some new constructor args created AbstractEngine class which provides base for SQLEngine and will also provide base for ConnectionProxy, so SQL binding can be to an engine or specific connection resource ClauseElements get using() method which can take AbstractEngines for execution made more separation between SchemaItems and bound engine</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunklibsqlalchemyextproxypy">sqlalchemy/trunk/lib/sqlalchemy/ext/proxy.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemymappingobjectstorepy">sqlalchemy/trunk/lib/sqlalchemy/mapping/objectstore.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemymappingquerypy">sqlalchemy/trunk/lib/sqlalchemy/mapping/query.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemyschemapy">sqlalchemy/trunk/lib/sqlalchemy/schema.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemysqlpy">sqlalchemy/trunk/lib/sqlalchemy/sql.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunklibsqlalchemyextproxypy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/ext/proxy.py (1264 => 1265)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/ext/proxy.py 2006-04-06 21:12:00 UTC (rev 1264) +++ sqlalchemy/trunk/lib/sqlalchemy/ext/proxy.py 2006-04-06 23:46:02 UTC (rev 1265) </span><span class="lines">@@ -24,7 +24,15 @@ </span><span class="cx"> </span><span class="cx"> def reflecttable(self, table): </span><span class="cx"> return self.get_engine().reflecttable(table) </span><del>- </del><ins>+ def execute_compiled(self, *args, **kwargs): + return self.get_engine().execute_compiled(*args, **kwargs) + def compiler(self, *args, **kwargs): + return self.get_engine().compiler(*args, **kwargs) + def schemagenerator(self, *args, **kwargs): + return self.get_engine().schemagenerator(*args, **kwargs) + def schemadropper(self, *args, **kwargs): + return self.get_engine().schemadropper(*args, **kwargs) + </ins><span class="cx"> def hash_key(self): </span><span class="cx"> return "%s(%s)" % (self.__class__.__name__, id(self)) </span><span class="cx"> </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemymappingobjectstorepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/mapping/objectstore.py (1264 => 1265)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/mapping/objectstore.py 2006-04-06 21:12:00 UTC (rev 1264) +++ sqlalchemy/trunk/lib/sqlalchemy/mapping/objectstore.py 2006-04-06 23:46:02 UTC (rev 1265) </span><span class="lines">@@ -17,7 +17,7 @@ </span><span class="cx"> class Session(object): </span><span class="cx"> """Maintains a UnitOfWork instance, including transaction state.""" </span><span class="cx"> </span><del>- def __init__(self, nest_on=None, hash_key=None): </del><ins>+ def __init__(self, hash_key=None, new_imap=True, import_session=None): </ins><span class="cx"> """Initialize the objectstore with a UnitOfWork registry. If called </span><span class="cx"> with no arguments, creates a single UnitOfWork for all operations. </span><span class="cx"> </span><span class="lines">@@ -26,31 +26,23 @@ </span><span class="cx"> hash_key - the hash_key used to identify objects against this session, which </span><span class="cx"> defaults to the id of the Session instance. </span><span class="cx"> """ </span><del>- self.uow = unitofwork.UnitOfWork() - self.parent_uow = None - self.begin_count = 0 - self.nest_on = util.to_list(nest_on) - self.__pushed_count = 0 </del><ins>+ if import_session is not None: + self.uow = unitofwork.UnitOfWork(identity_map=import_session.uow.identity_map) + elif new_imap is False: + self.uow = unitofwork.UnitOfWork(identity_map=objectstore.get_session().uow.identity_map) + else: + self.uow = unitofwork.UnitOfWork() + + self.binds = {} </ins><span class="cx"> if hash_key is None: </span><span class="cx"> self.hash_key = id(self) </span><span class="cx"> else: </span><span class="cx"> self.hash_key = hash_key </span><span class="cx"> _sessions[self.hash_key] = self </span><span class="cx"> </span><del>- def was_pushed(self): - if self.nest_on is None: - return - self.__pushed_count += 1 - if self.__pushed_count == 1: - for n in self.nest_on: - n.push_session() - def was_popped(self): - if self.nest_on is None or self.__pushed_count == 0: - return - self.__pushed_count -= 1 - if self.__pushed_count == 0: - for n in self.nest_on: - n.pop_session() </del><ins>+ def bind_table(self, table, bindto): + self.binds[table] = bindto + </ins><span class="cx"> def get_id_key(ident, class_, entity_name=None): </span><span class="cx"> """returns an identity-map key for use in storing/retrieving an item from the identity </span><span class="cx"> map, given a tuple of the object's primary key values. </span><span class="lines">@@ -81,79 +73,12 @@ </span><span class="cx"> """ </span><span class="cx"> return (class_, tuple([row[column] for column in primary_key]), entity_name) </span><span class="cx"> get_row_key = staticmethod(get_row_key) </span><del>- - class SessionTrans(object): - """returned by Session.begin(), denotes a transactionalized UnitOfWork instance. - call commit() on this to commit the transaction.""" - def __init__(self, parent, uow, isactive): - self.__parent = parent - self.__isactive = isactive - self.__uow = uow - isactive = property(lambda s:s.__isactive, doc="True if this SessionTrans is the 'active' transaction marker, else its a no-op.") - parent = property(lambda s:s.__parent, doc="returns the parent Session of this SessionTrans object.") - uow = property(lambda s:s.__uow, doc="returns the parent UnitOfWork corresponding to this transaction.") - def begin(self): - """calls begin() on the underlying Session object, returning a new no-op SessionTrans object.""" - if self.parent.uow is not self.uow: - raise InvalidRequestError("This SessionTrans is no longer valid") - return self.parent.begin() - def commit(self): - """commits the transaction noted by this SessionTrans object.""" - self.__parent._trans_commit(self) - self.__isactive = False - def rollback(self): - """rolls back the current UnitOfWork transaction, in the case that begin() - has been called. The changes logged since the begin() call are discarded.""" - self.__parent._trans_rollback(self) - self.__isactive = False - - def begin(self): - """begins a new UnitOfWork transaction and returns a tranasaction-holding - object. commit() or rollback() should be called on the returned object. - commit() on the Session will do nothing while a transaction is pending, and further - calls to begin() will return no-op transactional objects.""" - if self.parent_uow is not None: - return Session.SessionTrans(self, self.uow, False) - self.parent_uow = self.uow - self.uow = unitofwork.UnitOfWork(identity_map = self.uow.identity_map) - return Session.SessionTrans(self, self.uow, True) </del><span class="cx"> </span><span class="cx"> def engines(self, mapper): </span><span class="cx"> return [t.engine for t in mapper.tables] </span><span class="cx"> </span><del>- def _trans_commit(self, trans): - if trans.uow is self.uow and trans.isactive: - try: - self._commit_uow() - finally: - self.uow = self.parent_uow - self.parent_uow = None - def _trans_rollback(self, trans): - if trans.uow is self.uow: - self.uow = self.parent_uow - self.parent_uow = None - - def _commit_uow(self, *obj): - self.was_pushed() - try: - self.uow.flush(self, *obj) - finally: - self.was_popped() - - def commit(self, *objects): - """commits the current UnitOfWork transaction. called with - no arguments, this is only used - for "implicit" transactions when there was no begin(). - if individual objects are submitted, then only those objects are committed, and the - begin/commit cycle is not affected.""" - # if an object list is given, commit just those but dont - # change begin/commit status - if len(objects): - self._commit_uow(*objects) - self.uow.flush(self, *objects) - return - if self.parent_uow is None: - self._commit_uow() </del><ins>+ def flush(self, *obj): + self.uow.flush(self, *obj) </ins><span class="cx"> </span><span class="cx"> def refresh(self, *obj): </span><span class="cx"> """reloads the attributes for the given objects from the database, clears </span><span class="lines">@@ -221,6 +146,95 @@ </span><span class="cx"> u.register_new(instance) </span><span class="cx"> return instance </span><span class="cx"> </span><ins>+class LegacySession(Session): + def __init__(self, nest_on=None, hash_key=None, **kwargs): + super(LegacySession, self).__init__(**kwargs) + self.parent_uow = None + self.begin_count = 0 + self.nest_on = util.to_list(nest_on) + self.__pushed_count = 0 + def was_pushed(self): + if self.nest_on is None: + return + self.__pushed_count += 1 + if self.__pushed_count == 1: + for n in self.nest_on: + n.push_session() + def was_popped(self): + if self.nest_on is None or self.__pushed_count == 0: + return + self.__pushed_count -= 1 + if self.__pushed_count == 0: + for n in self.nest_on: + n.pop_session() + class SessionTrans(object): + """returned by Session.begin(), denotes a transactionalized UnitOfWork instance. + call commit() on this to commit the transaction.""" + def __init__(self, parent, uow, isactive): + self.__parent = parent + self.__isactive = isactive + self.__uow = uow + isactive = property(lambda s:s.__isactive, doc="True if this SessionTrans is the 'active' transaction marker, else its a no-op.") + parent = property(lambda s:s.__parent, doc="returns the parent Session of this SessionTrans object.") + uow = property(lambda s:s.__uow, doc="returns the parent UnitOfWork corresponding to this transaction.") + def begin(self): + """calls begin() on the underlying Session object, returning a new no-op SessionTrans object.""" + if self.parent.uow is not self.uow: + raise InvalidRequestError("This SessionTrans is no longer valid") + return self.parent.begin() + def commit(self): + """commits the transaction noted by this SessionTrans object.""" + self.__parent._trans_commit(self) + self.__isactive = False + def rollback(self): + """rolls back the current UnitOfWork transaction, in the case that begin() + has been called. The changes logged since the begin() call are discarded.""" + self.__parent._trans_rollback(self) + self.__isactive = False + def begin(self): + """begins a new UnitOfWork transaction and returns a tranasaction-holding + object. commit() or rollback() should be called on the returned object. + commit() on the Session will do nothing while a transaction is pending, and further + calls to begin() will return no-op transactional objects.""" + if self.parent_uow is not None: + return Session.SessionTrans(self, self.uow, False) + self.parent_uow = self.uow + self.uow = unitofwork.UnitOfWork(identity_map = self.uow.identity_map) + return Session.SessionTrans(self, self.uow, True) + def commit(self, *objects): + """commits the current UnitOfWork transaction. called with + no arguments, this is only used + for "implicit" transactions when there was no begin(). + if individual objects are submitted, then only those objects are committed, and the + begin/commit cycle is not affected.""" + # if an object list is given, commit just those but dont + # change begin/commit status + if len(objects): + self._commit_uow(*objects) + self.uow.flush(self, *objects) + return + if self.parent_uow is None: + self._commit_uow() + def _trans_commit(self, trans): + if trans.uow is self.uow and trans.isactive: + try: + self._commit_uow() + finally: + self.uow = self.parent_uow + self.parent_uow = None + def _trans_rollback(self, trans): + if trans.uow is self.uow: + self.uow = self.parent_uow + self.parent_uow = None + def _commit_uow(self, *obj): + self.was_pushed() + try: + self.uow.flush(self, *obj) + finally: + self.was_popped() + +Session = LegacySession + </ins><span class="cx"> def get_id_key(ident, class_, entity_name=None): </span><span class="cx"> return Session.get_id_key(ident, class_, entity_name) </span><span class="cx"> </span><span class="lines">@@ -228,19 +242,22 @@ </span><span class="cx"> return Session.get_row_key(row, class_, primary_key, entity_name) </span><span class="cx"> </span><span class="cx"> def begin(): </span><del>- """begins a new UnitOfWork transaction. the next commit will affect only - objects that are created, modified, or deleted following the begin statement.""" </del><ins>+ """deprecated. use s = Session(new_imap=False).""" </ins><span class="cx"> return get_session().begin() </span><span class="cx"> </span><span class="cx"> def commit(*obj): </span><del>- """commits the current UnitOfWork transaction. if a transaction was begun - via begin(), commits only those objects that were created, modified, or deleted - since that begin statement. otherwise commits all objects that have been </del><ins>+ """deprecated; use flush(*obj)""" + get_session().flush(*obj) + +def flush(*obj): + """flushes the current UnitOfWork transaction. if a transaction was begun + via begin(), flushes only those objects that were created, modified, or deleted + since that begin statement. otherwise flushes all objects that have been </ins><span class="cx"> changed. </span><del>- </del><ins>+ </ins><span class="cx"> if individual objects are submitted, then only those objects are committed, and the </span><span class="cx"> begin/commit cycle is not affected.""" </span><del>- get_session().commit(*obj) </del><ins>+ get_session().flush(*obj) </ins><span class="cx"> </span><span class="cx"> def clear(): </span><span class="cx"> """removes all current UnitOfWorks and IdentityMaps for this thread and </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemymappingquerypy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/mapping/query.py (1264 => 1265)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/mapping/query.py 2006-04-06 21:12:00 UTC (rev 1264) +++ sqlalchemy/trunk/lib/sqlalchemy/mapping/query.py 2006-04-06 23:46:02 UTC (rev 1265) </span><span class="lines">@@ -10,6 +10,7 @@ </span><span class="cx"> self.mapper = mapper </span><span class="cx"> self.always_refresh = kwargs.pop('always_refresh', self.mapper.always_refresh) </span><span class="cx"> self.order_by = kwargs.pop('order_by', self.mapper.order_by) </span><ins>+ self.extension = kwargs.pop('extension', self.mapper.extension) </ins><span class="cx"> self._session = kwargs.pop('session', None) </span><span class="cx"> if not hasattr(mapper, '_get_clause'): </span><span class="cx"> _get_clause = sql.and_() </span><span class="lines">@@ -66,7 +67,7 @@ </span><span class="cx"> </span><span class="cx"> e.g. result = usermapper.select_by(user_name = 'fred') </span><span class="cx"> """ </span><del>- ret = self.mapper.extension.select_by(self, *args, **params) </del><ins>+ ret = self.extension.select_by(self, *args, **params) </ins><span class="cx"> if ret is not mapper.EXT_PASS: </span><span class="cx"> return ret </span><span class="cx"> return self.select_whereclause(self._by_clause(*args, **params)) </span><span class="lines">@@ -116,7 +117,7 @@ </span><span class="cx"> in this case, the developer must insure that an adequate set of columns exists in the </span><span class="cx"> rowset with which to build new object instances.""" </span><span class="cx"> </span><del>- ret = self.mapper.extension.select(self, arg=arg, **kwargs) </del><ins>+ ret = self.extension.select(self, arg=arg, **kwargs) </ins><span class="cx"> if ret is not mapper.EXT_PASS: </span><span class="cx"> return ret </span><span class="cx"> elif arg is not None and isinstance(arg, sql.Selectable): </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemyschemapy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/schema.py (1264 => 1265)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/schema.py 2006-04-06 21:12:00 UTC (rev 1264) +++ sqlalchemy/trunk/lib/sqlalchemy/schema.py 2006-04-06 23:46:02 UTC (rev 1265) </span><span class="lines">@@ -23,8 +23,17 @@ </span><span class="cx"> __all__ = ['SchemaItem', 'Table', 'Column', 'ForeignKey', 'Sequence', 'Index', </span><span class="cx"> 'SchemaEngine', 'SchemaVisitor', 'PassiveDefault', 'ColumnDefault'] </span><span class="cx"> </span><ins>+class SchemaMeta(type): + """provides universal constructor arguments for all SchemaItems""" + def __call__(self, *args, **kwargs): + engine = kwargs.pop('engine', None) + obj = type.__call__(self, *args, **kwargs) + obj._engine = engine + return obj + </ins><span class="cx"> class SchemaItem(object): </span><span class="cx"> """base class for items that define a database schema.""" </span><ins>+ __metaclass__ = SchemaMeta </ins><span class="cx"> def _init_items(self, *args): </span><span class="cx"> for item in args: </span><span class="cx"> if item is not None: </span><span class="lines">@@ -34,7 +43,20 @@ </span><span class="cx"> raise NotImplementedError() </span><span class="cx"> def __repr__(self): </span><span class="cx"> return "%s()" % self.__class__.__name__ </span><del>- </del><ins>+ +class EngineMixin(object): + """a mixin for SchemaItems that provides an "engine" accessor.""" + def _derived_engine(self): + """subclasses override this method to return an AbstractEngine + bound to a parent item""" + return None + def _get_engine(self): + if self._engine is not None: + return self._engine + else: + return self._derived_engine() + engine = property(_get_engine) + </ins><span class="cx"> def _get_table_key(engine, name, schema): </span><span class="cx"> if schema is not None and schema == engine.get_default_schema_name(): </span><span class="cx"> schema = None </span><span class="lines">@@ -43,14 +65,12 @@ </span><span class="cx"> else: </span><span class="cx"> return schema + "." + name </span><span class="cx"> </span><del>-class TableSingleton(type): </del><ins>+class TableSingleton(SchemaMeta): </ins><span class="cx"> """a metaclass used by the Table object to provide singleton behavior.""" </span><span class="cx"> def __call__(self, name, engine=None, *args, **kwargs): </span><span class="cx"> try: </span><del>- if not isinstance(engine, SchemaEngine): </del><ins>+ if engine is not None and not isinstance(engine, SchemaEngine): </ins><span class="cx"> args = [engine] + list(args) </span><del>- engine = None - if engine is None: </del><span class="cx"> engine = default_engine </span><span class="cx"> name = str(name) # in case of incoming unicode </span><span class="cx"> schema = kwargs.get('schema', None) </span><span class="lines">@@ -58,6 +78,10 @@ </span><span class="cx"> redefine = kwargs.pop('redefine', False) </span><span class="cx"> mustexist = kwargs.pop('mustexist', False) </span><span class="cx"> useexisting = kwargs.pop('useexisting', False) </span><ins>+ if not engine: + table = type.__call__(self, name, engine, **kwargs) + table._init_items(*args) + return table </ins><span class="cx"> key = _get_table_key(engine, name, schema) </span><span class="cx"> table = engine.tables[key] </span><span class="cx"> if len(args): </span><span class="lines">@@ -440,15 +464,14 @@ </span><span class="cx"> self.parent.foreign_key = self </span><span class="cx"> self.parent.table.foreign_keys.append(self) </span><span class="cx"> </span><del>-class DefaultGenerator(SchemaItem): </del><ins>+class DefaultGenerator(SchemaItem, EngineMixin): </ins><span class="cx"> """Base class for column "default" values.""" </span><del>- def __init__(self, for_update=False, engine=None): </del><ins>+ def __init__(self, for_update=False): </ins><span class="cx"> self.for_update = for_update </span><del>- self.engine = engine </del><ins>+ def _derived_engine(self): + return self.column.table.engine </ins><span class="cx"> def _set_parent(self, column): </span><span class="cx"> self.column = column </span><del>- if self.engine is None: - self.engine = column.table.engine </del><span class="cx"> if self.for_update: </span><span class="cx"> self.column.onupdate = self </span><span class="cx"> else: </span><span class="lines">@@ -509,7 +532,7 @@ </span><span class="cx"> return visitor.visit_sequence(self) </span><span class="cx"> </span><span class="cx"> </span><del>-class Index(SchemaItem): </del><ins>+class Index(SchemaItem, EngineMixin): </ins><span class="cx"> """Represents an index of columns from a database table </span><span class="cx"> """ </span><span class="cx"> def __init__(self, name, *columns, **kw): </span><span class="lines">@@ -530,7 +553,8 @@ </span><span class="cx"> self.unique = kw.pop('unique', False) </span><span class="cx"> self._init_items(*columns) </span><span class="cx"> </span><del>- engine = property(lambda s:s.table.engine) </del><ins>+ def _derived_engine(self): + return self.table.engine </ins><span class="cx"> def _init_items(self, *args): </span><span class="cx"> for column in args: </span><span class="cx"> self.append_column(column) </span><span class="lines">@@ -570,18 +594,21 @@ </span><span class="cx"> for c in self.columns]), </span><span class="cx"> (self.unique and ', unique=True') or '') </span><span class="cx"> </span><del>-class SchemaEngine(object): </del><ins>+class SchemaEngine(sql.AbstractEngine): </ins><span class="cx"> """a factory object used to create implementations for schema objects. This object </span><span class="cx"> is the ultimate base class for the engine.SQLEngine class.""" </span><span class="cx"> </span><span class="cx"> def __init__(self): </span><span class="cx"> # a dictionary that stores Table objects keyed off their name (and possibly schema name) </span><span class="cx"> self.tables = {} </span><del>- </del><span class="cx"> def reflecttable(self, table): </span><span class="cx"> """given a table, will query the database and populate its Column and ForeignKey </span><span class="cx"> objects.""" </span><span class="cx"> raise NotImplementedError() </span><ins>+ def schemagenerator(self, **params): + raise NotImplementedError() + def schemadropper(self, **params): + raise NotImplementedError() </ins><span class="cx"> </span><span class="cx"> class SchemaVisitor(sql.ClauseVisitor): </span><span class="cx"> """defines the visiting for SchemaItem objects""" </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemysqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/sql.py (1264 => 1265)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/sql.py 2006-04-06 21:12:00 UTC (rev 1264) +++ sqlalchemy/trunk/lib/sqlalchemy/sql.py 2006-04-06 23:46:02 UTC (rev 1265) </span><span class="lines">@@ -246,6 +246,12 @@ </span><span class="cx"> def is_column(col): </span><span class="cx"> return isinstance(col, ColumnElement) </span><span class="cx"> </span><ins>+class AbstractEngine(object): + def execute_compiled(self, compiled, parameters, echo=None, **kwargs): + raise NotImplementedError() + def compiler(self, statement, parameters, **kwargs): + raise NotImplementedError() + </ins><span class="cx"> class ClauseParameters(util.OrderedDict): </span><span class="cx"> """represents a dictionary/iterator of bind parameter key names/values. Includes parameters compiled with a Compiled object as well as additional arguments passed to the Compiled object's get_params() method. Parameter values will be converted as per the TypeEngine objects present in the bind parameter objects. The non-converted value can be retrieved via the get_original method. For Compiled objects that compile positional parameters, the values() iteration of the object will return the parameter values in the correct order.""" </span><span class="cx"> def __init__(self, engine=None): </span><span class="lines">@@ -340,8 +346,11 @@ </span><span class="cx"> """executes this compiled object using the underlying SQLEngine""" </span><span class="cx"> if len(multiparams): </span><span class="cx"> params = multiparams </span><del>- - return self.engine.execute_compiled(self, params) </del><ins>+ + e = self.engine + if e is None: + raise InvalidRequestError("This Compiled object is not bound to any engine.") + return e.execute_compiled(self, params) </ins><span class="cx"> </span><span class="cx"> def scalar(self, *multiparams, **params): </span><span class="cx"> """executes this compiled object via the execute() method, then </span><span class="lines">@@ -356,7 +365,26 @@ </span><span class="cx"> return row[0] </span><span class="cx"> else: </span><span class="cx"> return None </span><del>- </del><ins>+ +class Executor(object): + """handles the compilation/execution of a ClauseElement within the context of a particular AbtractEngine. This + AbstractEngine will usually be a SQLEngine or ConnectionProxy.""" + def __init__(self, clauseelement, abstractengine=None): + self.engine=abstractengine + self.clauseelement = clauseelement + def execute(self, *multiparams, **params): + return self.compile(*multiparams, **params).execute(*multiparams, **params) + def scalar(self, *multiparams, **params): + return self.compile(*multiparams, **params).scalar(*multiparams, **params) + def compile(self, *multiparams, **params): + if len(multiparams): + bindparams = multiparams[0] + else: + bindparams = params + compiler = self.engine.compiler(self.clauseelement, bindparams) + compiler.compile() + return compiler + </ins><span class="cx"> class ClauseElement(object): </span><span class="cx"> """base class for elements of a programmatically constructed SQL expression.""" </span><span class="cx"> def _get_from_objects(self): </span><span class="lines">@@ -415,10 +443,12 @@ </span><span class="cx"> </span><span class="cx"> engine = property(lambda s: s._find_engine(), doc="attempts to locate a SQLEngine within this ClauseElement structure, or returns None if none found.") </span><span class="cx"> </span><del>- </del><ins>+ def using(self, abstractengine): + return Executor(self, abstractengine) + </ins><span class="cx"> def compile(self, engine = None, parameters = None, typemap=None, compiler=None): </span><span class="cx"> """compiles this SQL expression using its underlying SQLEngine to produce </span><del>- a Compiled object. If no engine can be found, an ansisql engine is used. </del><ins>+ a Compiled object. If no engine can be found, an ANSICompiler is used with no engine. </ins><span class="cx"> bindparams is a dictionary representing the default bind parameters to be used with </span><span class="cx"> the statement. """ </span><span class="cx"> </span><span class="lines">@@ -430,7 +460,7 @@ </span><span class="cx"> </span><span class="cx"> if compiler is None: </span><span class="cx"> import sqlalchemy.ansisql as ansisql </span><del>- compiler = ansisql.ANSICompiler(self, parameters=parameters, typemap=typemap) </del><ins>+ compiler = ansisql.ANSICompiler(self, parameters=parameters) </ins><span class="cx"> compiler.compile() </span><span class="cx"> return compiler </span><span class="cx"> </span><span class="lines">@@ -438,30 +468,10 @@ </span><span class="cx"> return str(self.compile()) </span><span class="cx"> </span><span class="cx"> def execute(self, *multiparams, **params): </span><del>- """compiles and executes this SQL expression using its underlying SQLEngine. the - given **params are used as bind parameters when compiling and executing the - expression. the DBAPI cursor object is returned.""" - e = self.engine - if len(multiparams): - bindparams = multiparams[0] - else: - bindparams = params - c = self.compile(e, parameters=bindparams) - return c.execute(*multiparams, **params) </del><ins>+ return self.using(self.engine).execute(*multiparams, **params) </ins><span class="cx"> </span><span class="cx"> def scalar(self, *multiparams, **params): </span><del>- """executes this SQL expression via the execute() method, then - returns the first column of the first row. Useful for executing functions, - sequences, rowcounts, etc.""" - # we are still going off the assumption that fetching only the first row - # in a result set is not performance-wise any different than specifying limit=1 - # else we'd have to construct a copy of the select() object with the limit - # installed (else if we change the existing select, not threadsafe) - row = self.execute(*multiparams, **params).fetchone() - if row is not None: - return row[0] - else: - return None </del><ins>+ return self.using(self.engine).scalar(*multiparams, **params) </ins><span class="cx"> </span><span class="cx"> def __and__(self, other): </span><span class="cx"> return and_(self, other) </span></span></pre> </div> </div> </body> </html> |