[Sqlalchemy-commits] [1039] sqlalchemy/trunk: merged sql_rearrangement branch , refactors sql packag
Brought to you by:
zzzeek
From: <co...@sq...> - 2006-02-25 07:13:04
|
<!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>[1039] sqlalchemy/trunk: merged sql_rearrangement branch , refactors sql package to work standalone with </title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1039</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-02-25 01:12:50 -0600 (Sat, 25 Feb 2006)</dd> </dl> <h3>Log Message</h3> <pre>merged sql_rearrangement branch , refactors sql package to work standalone with clause elements including tables and columns, schema package deals with "physical" representations</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunkCHANGES">sqlalchemy/trunk/CHANGES</a></li> <li><a href="#sqlalchemytrunklibsqlalchemy__init__py">sqlalchemy/trunk/lib/sqlalchemy/__init__.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemyansisqlpy">sqlalchemy/trunk/lib/sqlalchemy/ansisql.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemydatabasesmysqlpy">sqlalchemy/trunk/lib/sqlalchemy/databases/mysql.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemydatabasespostgrespy">sqlalchemy/trunk/lib/sqlalchemy/databases/postgres.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemyenginepy">sqlalchemy/trunk/lib/sqlalchemy/engine.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemyextproxypy">sqlalchemy/trunk/lib/sqlalchemy/ext/proxy.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemymappingmapperpy">sqlalchemy/trunk/lib/sqlalchemy/mapping/mapper.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemymappingobjectstorepy">sqlalchemy/trunk/lib/sqlalchemy/mapping/objectstore.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> <li><a href="#sqlalchemytrunklibsqlalchemyutilpy">sqlalchemy/trunk/lib/sqlalchemy/util.py</a></li> <li><a href="#sqlalchemytrunktestobjectstorepy">sqlalchemy/trunk/test/objectstore.py</a></li> <li><a href="#sqlalchemytrunktestselectpy">sqlalchemy/trunk/test/select.py</a></li> <li><a href="#sqlalchemytrunktesttestbasepy">sqlalchemy/trunk/test/testbase.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunkCHANGES"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/CHANGES (1038 => 1039)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/CHANGES 2006-02-25 07:06:09 UTC (rev 1038) +++ sqlalchemy/trunk/CHANGES 2006-02-25 07:12:50 UTC (rev 1039) </span><span class="lines">@@ -2,6 +2,9 @@ </span><span class="cx"> - fix to Oracle "row_number over" clause with mulitple tables </span><span class="cx"> - mapper.get() was not selecting multiple-keyed objects if the mapper's table was a join, </span><span class="cx"> such as in an inheritance relationship, this is fixed. </span><ins>+- overhaul to sql/schema packages so that the sql package can run all on its own, +producing selects, inserts, etc. without any engine dependencies. Table/Column +are the "physical" subclasses of TableClause/ColumnClause. </ins><span class="cx"> 0.1.2 </span><span class="cx"> - fixed a recursive call in schema that was somehow running 994 times then returning </span><span class="cx"> normally. broke nothing, slowed down everything. thanks to jpellerin for finding this. </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemy__init__py"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/__init__.py (1038 => 1039)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/__init__.py 2006-02-25 07:06:09 UTC (rev 1038) +++ sqlalchemy/trunk/lib/sqlalchemy/__init__.py 2006-02-25 07:12:50 UTC (rev 1039) </span><span class="lines">@@ -6,8 +6,8 @@ </span><span class="cx"> </span><span class="cx"> from engine import * </span><span class="cx"> from types import * </span><ins>+from sql import * </ins><span class="cx"> from schema import * </span><span class="cx"> from exceptions import * </span><del>-from sql import * </del><span class="cx"> import mapping as mapperlib </span><span class="cx"> from mapping import * </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemyansisqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/ansisql.py (1038 => 1039)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/ansisql.py 2006-02-25 07:06:09 UTC (rev 1038) +++ sqlalchemy/trunk/lib/sqlalchemy/ansisql.py 2006-02-25 07:12:50 UTC (rev 1039) </span><span class="lines">@@ -152,16 +152,11 @@ </span><span class="cx"> # if we are within a visit to a Select, set up the "typemap" </span><span class="cx"> # for this column which is used to translate result set values </span><span class="cx"> self.typemap.setdefault(column.key.lower(), column.type) </span><del>- if column.table.name is None: </del><ins>+ if column.table is not None and column.table.name is None: </ins><span class="cx"> self.strings[column] = column.name </span><span class="cx"> else: </span><span class="cx"> self.strings[column] = "%s.%s" % (column.table.name, column.name) </span><span class="cx"> </span><del>- def visit_columnclause(self, column): - if column.table is not None and column.table.name is not None: - self.strings[column] = "%s.%s" % (column.table.name, column.text) - else: - self.strings[column] = column.text </del><span class="cx"> </span><span class="cx"> def visit_fromclause(self, fromclause): </span><span class="cx"> self.froms[fromclause] = fromclause.from_name </span><span class="lines">@@ -257,11 +252,13 @@ </span><span class="cx"> l = co.label(co._label) </span><span class="cx"> l.accept_visitor(self) </span><span class="cx"> inner_columns[co._label] = l </span><del>- elif select.issubquery and isinstance(co, Column): </del><ins>+ # TODO: figure this out, a ColumnClause with a select as a parent + # is different from any other kind of parent + elif select.issubquery and isinstance(co, sql.ColumnClause) and co.table is not None and not isinstance(co.table, sql.Select): </ins><span class="cx"> # SQLite doesnt like selecting from a subquery where the column </span><span class="cx"> # names look like table.colname, so add a label synonomous with </span><span class="cx"> # the column name </span><del>- l = co.label(co.key) </del><ins>+ l = co.label(co.text) </ins><span class="cx"> l.accept_visitor(self) </span><span class="cx"> inner_columns[self.get_str(l.obj)] = l </span><span class="cx"> else: </span><span class="lines">@@ -379,7 +376,7 @@ </span><span class="cx"> contains a Sequence object.""" </span><span class="cx"> pass </span><span class="cx"> </span><del>- def visit_insert_column(selef, column): </del><ins>+ def visit_insert_column(self, column): </ins><span class="cx"> """called when visiting an Insert statement, for each column in the table </span><span class="cx"> that is a NULL insert into the table""" </span><span class="cx"> pass </span><span class="lines">@@ -395,8 +392,8 @@ </span><span class="cx"> self.visit_insert_sequence(c, seq) </span><span class="cx"> vis = DefaultVisitor() </span><span class="cx"> for c in insert_stmt.table.c: </span><del>- if (self.parameters is None or self.parameters.get(c.key, None) is None): - c.accept_visitor(vis) </del><ins>+ if (isinstance(c, schema.SchemaItem) and (self.parameters is None or self.parameters.get(c.key, None) is None)): + c.accept_schema_visitor(vis) </ins><span class="cx"> </span><span class="cx"> self.isinsert = True </span><span class="cx"> colparams = self._get_colparams(insert_stmt) </span><span class="lines">@@ -419,7 +416,7 @@ </span><span class="cx"> return self.bindparam_string(p.key) </span><span class="cx"> else: </span><span class="cx"> p.accept_visitor(self) </span><del>- if isinstance(p, sql.ClauseElement): </del><ins>+ if isinstance(p, sql.ClauseElement) and not isinstance(p, sql.ColumnClause): </ins><span class="cx"> return "(" + self.get_str(p) + ")" </span><span class="cx"> else: </span><span class="cx"> return self.get_str(p) </span><span class="lines">@@ -466,7 +463,7 @@ </span><span class="cx"> # now go thru compiled params, get the Column object for each key </span><span class="cx"> d = {} </span><span class="cx"> for key, value in parameters.iteritems(): </span><del>- if isinstance(key, schema.Column): </del><ins>+ if isinstance(key, sql.ColumnClause): </ins><span class="cx"> d[key] = value </span><span class="cx"> else: </span><span class="cx"> try: </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemydatabasesmysqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/databases/mysql.py (1038 => 1039)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/databases/mysql.py 2006-02-25 07:06:09 UTC (rev 1038) +++ sqlalchemy/trunk/lib/sqlalchemy/databases/mysql.py 2006-02-25 07:12:50 UTC (rev 1039) </span><span class="lines">@@ -131,11 +131,6 @@ </span><span class="cx"> def supports_sane_rowcount(self): </span><span class="cx"> return False </span><span class="cx"> </span><del>- def tableimpl(self, table, **kwargs): - """returns a new sql.TableImpl object to correspond to the given Table object.""" - mysql_engine = kwargs.pop('mysql_engine', None) - return MySQLTableImpl(table, mysql_engine=mysql_engine) - </del><span class="cx"> def compiler(self, statement, bindparams, **kwargs): </span><span class="cx"> return MySQLCompiler(self, statement, bindparams, **kwargs) </span><span class="cx"> </span><span class="lines">@@ -175,7 +170,7 @@ </span><span class="cx"> #ischema.reflecttable(self, table, ischema_names, use_mysql=True) </span><span class="cx"> </span><span class="cx"> tabletype, foreignkeyD = self.moretableinfo(table=table) </span><del>- table._impl.mysql_engine = tabletype </del><ins>+ table.kwargs['mysql_engine'] = tabletype </ins><span class="cx"> </span><span class="cx"> c = self.execute("describe " + table.name, {}) </span><span class="cx"> while True: </span><span class="lines">@@ -235,14 +230,6 @@ </span><span class="cx"> return (tabletype, foreignkeyD) </span><span class="cx"> </span><span class="cx"> </span><del>-class MySQLTableImpl(sql.TableImpl): - """attached to a schema.Table to provide it with a Selectable interface - as well as other functions - """ - def __init__(self, table, mysql_engine=None): - super(MySQLTableImpl, self).__init__(table) - self.mysql_engine = mysql_engine - </del><span class="cx"> class MySQLCompiler(ansisql.ANSICompiler): </span><span class="cx"> </span><span class="cx"> def visit_function(self, func): </span><span class="lines">@@ -277,12 +264,13 @@ </span><span class="cx"> if first_pk and isinstance(column.type, types.Integer): </span><span class="cx"> colspec += " AUTO_INCREMENT" </span><span class="cx"> if column.foreign_key: </span><del>- colspec += ", FOREIGN KEY (%s) REFERENCES %s(%s)" % (column.name, column.column.foreign_key.column.table.name, column.column.foreign_key.column.name) </del><ins>+ colspec += ", FOREIGN KEY (%s) REFERENCES %s(%s)" % (column.name, column.foreign_key.column.table.name, column.foreign_key.column.name) </ins><span class="cx"> return colspec </span><span class="cx"> </span><span class="cx"> def post_create_table(self, table): </span><del>- if table.mysql_engine is not None: - return " ENGINE=%s" % table.mysql_engine </del><ins>+ mysql_engine = table.kwargs.get('mysql_engine', None) + if mysql_engine is not None: + return " ENGINE=%s" % mysql_engine </ins><span class="cx"> else: </span><span class="cx"> return "" </span><span class="cx"> </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemydatabasespostgrespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/databases/postgres.py (1038 => 1039)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/databases/postgres.py 2006-02-25 07:06:09 UTC (rev 1038) +++ sqlalchemy/trunk/lib/sqlalchemy/databases/postgres.py 2006-02-25 07:12:50 UTC (rev 1039) </span><span class="lines">@@ -312,7 +312,7 @@ </span><span class="cx"> if column.primary_key and not override_pk: </span><span class="cx"> colspec += " PRIMARY KEY" </span><span class="cx"> if column.foreign_key: </span><del>- colspec += " REFERENCES %s(%s)" % (column.column.foreign_key.column.table.fullname, column.column.foreign_key.column.name) </del><ins>+ colspec += " REFERENCES %s(%s)" % (column.foreign_key.column.table.fullname, column.foreign_key.column.name) </ins><span class="cx"> return colspec </span><span class="cx"> </span><span class="cx"> def visit_sequence(self, sequence): </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemyenginepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/engine.py (1038 => 1039)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/engine.py 2006-02-25 07:06:09 UTC (rev 1038) +++ sqlalchemy/trunk/lib/sqlalchemy/engine.py 2006-02-25 07:12:50 UTC (rev 1039) </span><span class="lines">@@ -16,8 +16,7 @@ </span><span class="cx"> of DBAPI, and is the central switching point for abstracting different kinds of database </span><span class="cx"> behavior into a consistent set of behaviors. It provides a variety of factory methods </span><span class="cx"> to produce everything specific to a certain kind of database, including a Compiler, </span><del>-schema creation/dropping objects, and TableImpl and ColumnImpl objects to augment the -behavior of table metadata objects. </del><ins>+schema creation/dropping objects. </ins><span class="cx"> </span><span class="cx"> The term "database-specific" will be used to describe any object or function that has behavior </span><span class="cx"> corresponding to a particular vendor, such as mysql-specific, sqlite-specific, etc. </span><span class="lines">@@ -131,7 +130,7 @@ </span><span class="cx"> </span><span class="cx"> def get_column_default(self, column): </span><span class="cx"> if column.default is not None: </span><del>- return column.default.accept_visitor(self) </del><ins>+ return column.default.accept_schema_visitor(self) </ins><span class="cx"> else: </span><span class="cx"> return None </span><span class="cx"> </span><span class="lines">@@ -296,11 +295,11 @@ </span><span class="cx"> </span><span class="cx"> def create(self, entity, **params): </span><span class="cx"> """creates a table or index within this engine's database connection given a schema.Table object.""" </span><del>- entity.accept_visitor(self.schemagenerator(**params)) </del><ins>+ entity.accept_schema_visitor(self.schemagenerator(**params)) </ins><span class="cx"> </span><span class="cx"> def drop(self, entity, **params): </span><span class="cx"> """drops a table or index within this engine's database connection given a schema.Table object.""" </span><del>- entity.accept_visitor(self.schemadropper(**params)) </del><ins>+ entity.accept_schema_visitor(self.schemadropper(**params)) </ins><span class="cx"> </span><span class="cx"> def compile(self, statement, parameters, **kwargs): </span><span class="cx"> """given a sql.ClauseElement statement plus optional bind parameters, creates a new </span><span class="lines">@@ -315,28 +314,6 @@ </span><span class="cx"> """given a Table object, reflects its columns and properties from the database.""" </span><span class="cx"> raise NotImplementedError() </span><span class="cx"> </span><del>- def tableimpl(self, table, **kwargs): - """returns a new sql.TableImpl object to correspond to the given Table object. - A TableImpl provides SQL statement builder operations on a Table metadata object, - and a subclass of this object may be provided by a SQLEngine subclass to provide - database-specific behavior.""" - return sql.TableImpl(table) - - def columnimpl(self, column): - """returns a new sql.ColumnImpl object to correspond to the given Column object. - A ColumnImpl provides SQL statement builder operations on a Column metadata object, - and a subclass of this object may be provided by a SQLEngine subclass to provide - database-specific behavior.""" - return sql.ColumnImpl(column) - - def indeximpl(self, index): - """returns a new sql.IndexImpl object to correspond to the given Index - object. An IndexImpl provides SQL statement builder operations on an - Index metadata object, and a subclass of this object may be provided - by a SQLEngine subclass to provide database-specific behavior. - """ - return sql.IndexImpl(index) - </del><span class="cx"> def get_default_schema_name(self): </span><span class="cx"> """returns the currently selected schema in the current connection.""" </span><span class="cx"> return None </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemyextproxypy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/ext/proxy.py (1038 => 1039)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/ext/proxy.py 2006-02-25 07:06:09 UTC (rev 1038) +++ sqlalchemy/trunk/lib/sqlalchemy/ext/proxy.py 2006-02-25 07:12:50 UTC (rev 1039) </span><span class="lines">@@ -13,7 +13,7 @@ </span><span class="cx"> """ </span><span class="cx"> SQLEngine proxy. Supports lazy and late initialization by </span><span class="cx"> delegating to a real engine (set with connect()), and using proxy </span><del>- classes for TableImpl, ColumnImpl and TypeEngine. </del><ins>+ classes for TypeEngine. </ins><span class="cx"> """ </span><span class="cx"> </span><span class="cx"> def __init__(self): </span><span class="lines">@@ -61,15 +61,6 @@ </span><span class="cx"> return None </span><span class="cx"> return self.get_engine().oid_column_name() </span><span class="cx"> </span><del>- def columnimpl(self, column): - """Proxy point: return a ProxyColumnImpl - """ - return ProxyColumnImpl(self, column) - - def tableimpl(self, table): - """Proxy point: return a ProxyTableImpl - """ - return ProxyTableImpl(self, table) </del><span class="cx"> </span><span class="cx"> def type_descriptor(self, typeobj): </span><span class="cx"> """Proxy point: return a ProxyTypeEngine </span><span class="lines">@@ -84,45 +75,6 @@ </span><span class="cx"> raise AttributeError('No connection established in ProxyEngine: ' </span><span class="cx"> ' no access to %s' % attr) </span><span class="cx"> </span><del>- -class ProxyColumnImpl(sql.ColumnImpl): - """Proxy column; defers engine access to ProxyEngine - """ - def __init__(self, engine, column): - sql.ColumnImpl.__init__(self, column) - self._engine = engine - self.impls = weakref.WeakKeyDictionary() - def _get_impl(self): - e = self._engine.engine - try: - return self.impls[e] - except KeyError: - impl = e.columnimpl(self.column) - self.impls[e] = impl - def __getattr__(self, key): - return getattr(self._get_impl(), key) - engine = property(lambda self: self._engine.engine) - -class ProxyTableImpl(sql.TableImpl): - """Proxy table; defers engine access to ProxyEngine - """ - def __init__(self, engine, table): - sql.TableImpl.__init__(self, table) - self._engine = engine - self.impls = weakref.WeakKeyDictionary() - def _get_impl(self): - e = self._engine.engine - try: - return self.impls[e] - except KeyError: - impl = e.tableimpl(self.table) - self.impls[e] = impl - return impl - def __getattr__(self, key): - return getattr(self._get_impl(), key) - - engine = property(lambda self: self._engine.engine) - </del><span class="cx"> class ProxyType(object): </span><span class="cx"> """ProxyType base class; used by ProxyTypeEngine to construct proxying </span><span class="cx"> types </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemymappingmapperpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/mapping/mapper.py (1038 => 1039)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/mapping/mapper.py 2006-02-25 07:06:09 UTC (rev 1038) +++ sqlalchemy/trunk/lib/sqlalchemy/mapping/mapper.py 2006-02-25 07:12:50 UTC (rev 1039) </span><span class="lines">@@ -262,7 +262,7 @@ </span><span class="cx"> """returns an instance of the object based on the given identifier, or None </span><span class="cx"> if not found. The *ident argument is a </span><span class="cx"> list of primary key columns in the order of the table def's primary key columns.""" </span><del>- key = objectstore.get_id_key(ident, self.class_, self.primarytable) </del><ins>+ key = objectstore.get_id_key(ident, self.class_) </ins><span class="cx"> #print "key: " + repr(key) + " ident: " + repr(ident) </span><span class="cx"> return self._get(key, ident) </span><span class="cx"> </span><span class="lines">@@ -284,7 +284,7 @@ </span><span class="cx"> </span><span class="cx"> </span><span class="cx"> def identity_key(self, *primary_key): </span><del>- return objectstore.get_id_key(tuple(primary_key), self.class_, self.primarytable) </del><ins>+ return objectstore.get_id_key(tuple(primary_key), self.class_) </ins><span class="cx"> </span><span class="cx"> def instance_key(self, instance): </span><span class="cx"> return self.identity_key(*[self._getattrbycolumn(instance, column) for column in self.pks_by_table[self.table]]) </span><span class="lines">@@ -683,7 +683,7 @@ </span><span class="cx"> return statement </span><span class="cx"> </span><span class="cx"> def _identity_key(self, row): </span><del>- return objectstore.get_row_key(row, self.class_, self.identitytable, self.pks_by_table[self.table]) </del><ins>+ return objectstore.get_row_key(row, self.class_, self.pks_by_table[self.table]) </ins><span class="cx"> </span><span class="cx"> def _instance(self, row, imap, result = None, populate_existing = False): </span><span class="cx"> """pulls an object instance from the given row and appends it to the given result </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemymappingobjectstorepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/mapping/objectstore.py (1038 => 1039)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/mapping/objectstore.py 2006-02-25 07:06:09 UTC (rev 1038) +++ sqlalchemy/trunk/lib/sqlalchemy/mapping/objectstore.py 2006-02-25 07:12:50 UTC (rev 1039) </span><span class="lines">@@ -48,7 +48,7 @@ </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 get_id_key(ident, class_, table): </del><ins>+ def get_id_key(ident, class_): </ins><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="cx"> </span><span class="lines">@@ -62,10 +62,10 @@ </span><span class="cx"> selectable - a Selectable object which represents all the object's column-based fields. </span><span class="cx"> this Selectable may be synonymous with the table argument or can be a larger construct </span><span class="cx"> containing that table. return value: a tuple object which is used as an identity key. """ </span><del>- return (class_, table.hash_key(), tuple(ident)) </del><ins>+ return (class_, tuple(ident)) </ins><span class="cx"> get_id_key = staticmethod(get_id_key) </span><span class="cx"> </span><del>- def get_row_key(row, class_, table, primary_key): </del><ins>+ def get_row_key(row, class_, primary_key): </ins><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 result set row. </span><span class="cx"> </span><span class="lines">@@ -80,7 +80,7 @@ </span><span class="cx"> this Selectable may be synonymous with the table argument or can be a larger construct </span><span class="cx"> containing that table. return value: a tuple object which is used as an identity key. </span><span class="cx"> """ </span><del>- return (class_, table.hash_key(), tuple([row[column] for column in primary_key])) </del><ins>+ return (class_, tuple([row[column] for column in primary_key])) </ins><span class="cx"> get_row_key = staticmethod(get_row_key) </span><span class="cx"> </span><span class="cx"> class SessionTrans(object): </span><span class="lines">@@ -181,7 +181,6 @@ </span><span class="cx"> return None </span><span class="cx"> key = getattr(instance, '_instance_key', None) </span><span class="cx"> mapper = object_mapper(instance) </span><del>- key = (key[0], mapper.table.hash_key(), key[2]) </del><span class="cx"> u = self.uow </span><span class="cx"> if key is not None: </span><span class="cx"> if u.identity_map.has_key(key): </span><span class="lines">@@ -194,11 +193,11 @@ </span><span class="cx"> u.register_new(instance) </span><span class="cx"> return instance </span><span class="cx"> </span><del>-def get_id_key(ident, class_, table): - return Session.get_id_key(ident, class_, table) </del><ins>+def get_id_key(ident, class_): + return Session.get_id_key(ident, class_) </ins><span class="cx"> </span><del>-def get_row_key(row, class_, table, primary_key): - return Session.get_row_key(row, class_, table, primary_key) </del><ins>+def get_row_key(row, class_, primary_key): + return Session.get_row_key(row, class_, primary_key) </ins><span class="cx"> </span><span class="cx"> def begin(): </span><span class="cx"> """begins a new UnitOfWork transaction. the next commit will affect only </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemyschemapy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/schema.py (1038 => 1039)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/schema.py 2006-02-25 07:06:09 UTC (rev 1038) +++ sqlalchemy/trunk/lib/sqlalchemy/schema.py 2006-02-25 07:12:50 UTC (rev 1039) </span><span class="lines">@@ -14,7 +14,7 @@ </span><span class="cx"> the schema package "plugs in" to the SQL package. </span><span class="cx"> </span><span class="cx"> """ </span><del>- </del><ins>+import sql </ins><span class="cx"> from util import * </span><span class="cx"> from types import * </span><span class="cx"> from exceptions import * </span><span class="lines">@@ -29,30 +29,12 @@ </span><span class="cx"> for item in args: </span><span class="cx"> if item is not None: </span><span class="cx"> item._set_parent(self) </span><del>- - def accept_visitor(self, visitor): - """all schema items implement an accept_visitor method that should call the appropriate - visit_XXXX method upon the given visitor object.""" - raise NotImplementedError() - </del><span class="cx"> def _set_parent(self, parent): </span><span class="cx"> """a child item attaches itself to its parent via this method.""" </span><span class="cx"> raise NotImplementedError() </span><del>- - def hash_key(self): - """returns a string that identifies this SchemaItem uniquely""" - return "%s(%d)" % (self.__class__.__name__, id(self)) - </del><span class="cx"> def __repr__(self): </span><span class="cx"> return "%s()" % self.__class__.__name__ </span><span class="cx"> </span><del>- def __getattr__(self, key): - """proxies method calls to an underlying implementation object for methods not found - locally""" - if not self.__dict__.has_key('_impl'): - raise AttributeError(key) - return getattr(self._impl, key) - </del><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">@@ -95,8 +77,10 @@ </span><span class="cx"> return table </span><span class="cx"> </span><span class="cx"> </span><del>-class Table(SchemaItem): - """represents a relational database table. </del><ins>+class Table(sql.TableClause, SchemaItem): + """represents a relational database table. This subclasses sql.TableClause to provide + a table that is "wired" to an engine. Whereas TableClause represents a table as its + used in a SQL expression, Table represents a table as its created in the database. </ins><span class="cx"> </span><span class="cx"> Be sure to look at sqlalchemy.sql.TableImpl for additional methods defined on a Table.""" </span><span class="cx"> __metaclass__ = TableSingleton </span><span class="lines">@@ -134,19 +118,15 @@ </span><span class="cx"> the same table twice will result in an exception. </span><span class="cx"> </span><span class="cx"> """ </span><del>- self.name = name - self.columns = OrderedProperties() - self.c = self.columns - self.foreign_keys = [] - self.primary_key = [] - self.engine = engine </del><ins>+ super(Table, self).__init__(name) + self._engine = engine </ins><span class="cx"> self.schema = kwargs.pop('schema', None) </span><del>- self._impl = self.engine.tableimpl(self, **kwargs) </del><span class="cx"> if self.schema is not None: </span><span class="cx"> self.fullname = "%s.%s" % (self.schema, self.name) </span><span class="cx"> else: </span><span class="cx"> self.fullname = self.name </span><del>- </del><ins>+ self.kwargs = kwargs + </ins><span class="cx"> def __repr__(self): </span><span class="cx"> return "Table(%s)" % string.join( </span><span class="cx"> [repr(self.name)] + [repr(self.engine)] + </span><span class="lines">@@ -160,44 +140,45 @@ </span><span class="cx"> else: </span><span class="cx"> return self.schema + "." + self.name </span><span class="cx"> </span><del>- def hash_key(self): - return "Table(%s)" % string.join( - [repr(self.name)] + [self.engine.hash_key()] + - ["%s=%s" % (k, repr(getattr(self, k))) for k in ['schema']], ',' - ) - </del><span class="cx"> def reload_values(self, *args): </span><span class="cx"> """clears out the columns and other properties of this Table, and reloads them from the </span><span class="cx"> given argument list. This is used with the "redefine" keyword argument sent to the </span><span class="cx"> metaclass constructor.""" </span><del>- self.columns = OrderedProperties() - self.c = self.columns - self.foreign_keys = [] - self.primary_key = [] - self._impl = self.engine.tableimpl(self) </del><ins>+ self._clear() + + print "RELOAD VALUES", args </ins><span class="cx"> self._init_items(*args) </span><span class="cx"> </span><span class="cx"> def append_item(self, item): </span><span class="cx"> """appends a Column item or other schema item to this Table.""" </span><span class="cx"> self._init_items(item) </span><del>- </del><ins>+ + def append_column(self, column): + if not column.hidden: + self._columns[column.key] = column + if column.primary_key: + self.primary_key.append(column) + column.table = self + column.type = self.engine.type_descriptor(column.type) + </ins><span class="cx"> def _set_parent(self, schema): </span><span class="cx"> schema.tables[self.name] = self </span><span class="cx"> self.schema = schema </span><del>- - def accept_visitor(self, visitor): </del><ins>+ def accept_schema_visitor(self, visitor): </ins><span class="cx"> """traverses the given visitor across the Column objects inside this Table, </span><span class="cx"> then calls the visit_table method on the visitor.""" </span><span class="cx"> for c in self.columns: </span><del>- c.accept_visitor(visitor) </del><ins>+ c.accept_schema_visitor(visitor) </ins><span class="cx"> return visitor.visit_table(self) </span><del>- </del><span class="cx"> def deregister(self): </span><span class="cx"> """removes this table from it's engines table registry. this does not </span><span class="cx"> issue a SQL DROP statement.""" </span><span class="cx"> key = _get_table_key(self.engine, self.name, self.schema) </span><span class="cx"> del self.engine.tables[key] </span><del>- </del><ins>+ def create(self, **params): + self.engine.create(self) + def drop(self, **params): + self.engine.drop(self) </ins><span class="cx"> def toengine(self, engine, schema=None): </span><span class="cx"> """returns a singleton instance of this Table with a different engine""" </span><span class="cx"> try: </span><span class="lines">@@ -211,8 +192,9 @@ </span><span class="cx"> args.append(c.copy()) </span><span class="cx"> return Table(self.name, engine, schema=schema, *args) </span><span class="cx"> </span><del>-class Column(SchemaItem): - """represents a column in a database table.""" </del><ins>+class Column(sql.ColumnClause, SchemaItem): + """represents a column in a database table. this is a subclass of sql.ColumnClause and + represents an actual existing table in the database, in a similar fashion as TableClause/Table.""" </ins><span class="cx"> def __init__(self, name, type, *args, **kwargs): </span><span class="cx"> """constructs a new Column object. Arguments are: </span><span class="cx"> </span><span class="lines">@@ -244,24 +226,27 @@ </span><span class="cx"> hidden=False : indicates this column should not be listed in the table's list of columns. Used for the "oid" </span><span class="cx"> column, which generally isnt in column lists. </span><span class="cx"> """ </span><del>- self.name = str(name) # in case of incoming unicode - self.type = type </del><ins>+ name = str(name) # in case of incoming unicode + super(Column, self).__init__(name, None, type) </ins><span class="cx"> self.args = args </span><span class="cx"> self.key = kwargs.pop('key', name) </span><del>- self.primary_key = kwargs.pop('primary_key', False) </del><ins>+ self._primary_key = kwargs.pop('primary_key', False) </ins><span class="cx"> self.nullable = kwargs.pop('nullable', not self.primary_key) </span><span class="cx"> self.hidden = kwargs.pop('hidden', False) </span><span class="cx"> self.default = kwargs.pop('default', None) </span><del>- self.foreign_key = None </del><ins>+ self._foreign_key = None </ins><span class="cx"> self._orig = None </span><span class="cx"> self._parent = None </span><span class="cx"> if len(kwargs): </span><span class="cx"> raise ArgumentError("Unknown arguments passed to Column: " + repr(kwargs.keys())) </span><del>- </del><ins>+ + primary_key = AttrProp('_primary_key') + foreign_key = AttrProp('_foreign_key') </ins><span class="cx"> original = property(lambda s: s._orig or s) </span><span class="cx"> parent = property(lambda s:s._parent or s) </span><span class="cx"> engine = property(lambda s: s.table.engine) </span><del>- </del><ins>+ columns = property(lambda self:[self]) + </ins><span class="cx"> def __repr__(self): </span><span class="cx"> return "Column(%s)" % string.join( </span><span class="cx"> [repr(self.name)] + [repr(self.type)] + </span><span class="lines">@@ -282,16 +267,7 @@ </span><span class="cx"> def _set_parent(self, table): </span><span class="cx"> if getattr(self, 'table', None) is not None: </span><span class="cx"> raise ArgumentError("this Column already has a table!") </span><del>- if not self.hidden: - table.columns[self.key] = self - if self.primary_key: - table.primary_key.append(self) - self.table = table - if self.table.engine is not None: - self.type = self.table.engine.type_descriptor(self.type) - - self._impl = self.table.engine.columnimpl(self) - </del><ins>+ table.append_column(self) </ins><span class="cx"> if self.default is not None: </span><span class="cx"> self.default = ColumnDefault(self.default) </span><span class="cx"> self._init_items(self.default) </span><span class="lines">@@ -320,35 +296,19 @@ </span><span class="cx"> selectable.columns[c.key] = c </span><span class="cx"> if self.primary_key: </span><span class="cx"> selectable.primary_key.append(c) </span><del>- c._impl = self.engine.columnimpl(c) </del><span class="cx"> if fk is not None: </span><span class="cx"> c._init_items(fk) </span><span class="cx"> return c </span><span class="cx"> </span><del>- def accept_visitor(self, visitor): </del><ins>+ def accept_schema_visitor(self, visitor): </ins><span class="cx"> """traverses the given visitor to this Column's default and foreign key object, </span><span class="cx"> then calls visit_column on the visitor.""" </span><span class="cx"> if self.default is not None: </span><del>- self.default.accept_visitor(visitor) </del><ins>+ self.default.accept_schema_visitor(visitor) </ins><span class="cx"> if self.foreign_key is not None: </span><del>- self.foreign_key.accept_visitor(visitor) </del><ins>+ self.foreign_key.accept_schema_visitor(visitor) </ins><span class="cx"> visitor.visit_column(self) </span><span class="cx"> </span><del>- def __lt__(self, other): return self._impl.__lt__(other) - def __le__(self, other): return self._impl.__le__(other) - def __eq__(self, other): return self._impl.__eq__(other) - def __ne__(self, other): return self._impl.__ne__(other) - def __gt__(self, other): return self._impl.__gt__(other) - def __ge__(self, other): return self._impl.__ge__(other) - def __add__(self, other): return self._impl.__add__(other) - def __sub__(self, other): return self._impl.__sub__(other) - def __mul__(self, other): return self._impl.__mul__(other) - def __and__(self, other): return self._impl.__and__(other) - def __or__(self, other): return self._impl.__or__(other) - def __div__(self, other): return self._impl.__div__(other) - def __truediv__(self, other): return self._impl.__truediv__(other) - def __invert__(self, other): return self._impl.__invert__(other) - def __str__(self): return self._impl.__str__() </del><span class="cx"> </span><span class="cx"> class ForeignKey(SchemaItem): </span><span class="cx"> """defines a ForeignKey constraint between two columns. ForeignKey is </span><span class="lines">@@ -374,7 +334,7 @@ </span><span class="cx"> elif self._colspec.table.schema is not None: </span><span class="cx"> return "%s.%s.%s" % (self._colspec.table.schema, self._colspec.table.name, self._colspec.column.key) </span><span class="cx"> else: </span><del>- return "%s.%s" % (self._colspec.table.name, self._colspec.column.key) </del><ins>+ return "%s.%s" % (self._colspec.table.name, self._colspec.key) </ins><span class="cx"> </span><span class="cx"> def references(self, table): </span><span class="cx"> """returns True if the given table is referenced by this ForeignKey.""" </span><span class="lines">@@ -406,7 +366,7 @@ </span><span class="cx"> </span><span class="cx"> column = property(lambda s: s._init_column()) </span><span class="cx"> </span><del>- def accept_visitor(self, visitor): </del><ins>+ def accept_schema_visitor(self, visitor): </ins><span class="cx"> """calls the visit_foreign_key method on the given visitor.""" </span><span class="cx"> visitor.visit_foreign_key(self) </span><span class="cx"> </span><span class="lines">@@ -432,7 +392,7 @@ </span><span class="cx"> """a default that takes effect on the database side""" </span><span class="cx"> def __init__(self, arg): </span><span class="cx"> self.arg = arg </span><del>- def accept_visitor(self, visitor): </del><ins>+ def accept_schema_visitor(self, visitor): </ins><span class="cx"> return visitor.visit_passive_default(self) </span><span class="cx"> def __repr__(self): </span><span class="cx"> return "PassiveDefault(%s)" % repr(self.arg) </span><span class="lines">@@ -442,7 +402,7 @@ </span><span class="cx"> a callable function, or a SQL clause.""" </span><span class="cx"> def __init__(self, arg): </span><span class="cx"> self.arg = arg </span><del>- def accept_visitor(self, visitor): </del><ins>+ def accept_schema_visitor(self, visitor): </ins><span class="cx"> """calls the visit_column_default method on the given visitor.""" </span><span class="cx"> return visitor.visit_column_default(self) </span><span class="cx"> def __repr__(self): </span><span class="lines">@@ -461,7 +421,7 @@ </span><span class="cx"> ["%s=%s" % (k, repr(getattr(self, k))) for k in ['start', 'increment', 'optional']] </span><span class="cx"> , ',') </span><span class="cx"> </span><del>- def accept_visitor(self, visitor): </del><ins>+ def accept_schema_visitor(self, visitor): </ins><span class="cx"> """calls the visit_seauence method on the given visitor.""" </span><span class="cx"> return visitor.visit_sequence(self) </span><span class="cx"> </span><span class="lines">@@ -486,6 +446,7 @@ </span><span class="cx"> self.unique = kw.pop('unique', False) </span><span class="cx"> self._init_items() </span><span class="cx"> </span><ins>+ engine = property(lambda s:s.table.engine) </ins><span class="cx"> def _init_items(self): </span><span class="cx"> # make sure all columns are from the same table </span><span class="cx"> # FIXME: and no column is repeated </span><span class="lines">@@ -499,10 +460,13 @@ </span><span class="cx"> "%s is from %s not %s" % (column, </span><span class="cx"> column.table, </span><span class="cx"> self.table)) </span><del>- # set my _impl from col.table.engine - self._impl = self.table.engine.indeximpl(self) - - def accept_visitor(self, visitor): </del><ins>+ def create(self): + self.engine.create(self) + def drop(self): + self.engine.drop(self) + def execute(self): + self.create() + def accept_schema_visitor(self, visitor): </ins><span class="cx"> visitor.visit_index(self) </span><span class="cx"> def __str__(self): </span><span class="cx"> return repr(self) </span><span class="lines">@@ -515,24 +479,13 @@ </span><span class="cx"> class SchemaEngine(object): </span><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><del>- def tableimpl(self, table): - """returns a new implementation object for a Table (usually sql.TableImpl)""" - raise NotImplementedError() - def columnimpl(self, column): - """returns a new implementation object for a Column (usually sql.ColumnImpl)""" - raise NotImplementedError() - def indeximpl(self, index): - """returns a new implementation object for an Index (usually - sql.IndexImpl) - """ - raise NotImplementedError() </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><span class="cx"> </span><del>-class SchemaVisitor(object): - """base class for an object that traverses across Schema structures.""" </del><ins>+class SchemaVisitor(sql.ClauseVisitor): + """defines the visiting for SchemaItem objects""" </ins><span class="cx"> def visit_schema(self, schema): </span><span class="cx"> """visit a generic SchemaItem""" </span><span class="cx"> pass </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemysqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/sql.py (1038 => 1039)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/sql.py 2006-02-25 07:06:09 UTC (rev 1038) +++ sqlalchemy/trunk/lib/sqlalchemy/sql.py 2006-02-25 07:12:50 UTC (rev 1039) </span><span class="lines">@@ -13,7 +13,7 @@ </span><span class="cx"> import string, re, random </span><span class="cx"> types = __import__('types') </span><span class="cx"> </span><del>-__all__ = ['text', 'column', 'func', 'select', 'update', 'insert', 'delete', 'join', 'and_', 'or_', 'not_', 'union', 'union_all', 'desc', 'asc', 'outerjoin', 'alias', 'subquery', 'literal', 'bindparam', 'exists'] </del><ins>+__all__ = ['text', 'table', 'column', 'func', 'select', 'update', 'insert', 'delete', 'join', 'and_', 'or_', 'not_', 'union', 'union_all', 'desc', 'asc', 'outerjoin', 'alias', 'subquery', 'literal', 'bindparam', 'exists'] </ins><span class="cx"> </span><span class="cx"> def desc(column): </span><span class="cx"> """returns a descending ORDER BY clause element, e.g.: </span><span class="lines">@@ -160,11 +160,15 @@ </span><span class="cx"> """returns a Label object for the given selectable, used in the column list for a select statement.""" </span><span class="cx"> return Label(name, obj) </span><span class="cx"> </span><del>-def column(table, text): - """returns a textual column clause, relative to a table. this differs from using straight text - or text() in that the column is treated like a regular column, i.e. gets added to a Selectable's list - of columns.""" - return ColumnClause(text, table) </del><ins>+def column(text, table=None, type=None): + """returns a textual column clause, relative to a table. this is also the primitive version of + a schema.Column which is a subclass. """ + return ColumnClause(text, table, type) + +def table(name, *columns): + """returns a table clause. this is a primitive version of the schema.Table object, which is a subclass + of this object.""" + return TableClause(name, *columns) </ins><span class="cx"> </span><span class="cx"> def bindparam(key, value = None, type=None): </span><span class="cx"> """creates a bind parameter clause with the given key. </span><span class="lines">@@ -172,7 +176,7 @@ </span><span class="cx"> An optional default value can be specified by the value parameter, and the optional type parameter </span><span class="cx"> is a sqlalchemy.types.TypeEngine object which indicates bind-parameter and result-set translation for </span><span class="cx"> this bind parameter.""" </span><del>- if isinstance(key, schema.Column): </del><ins>+ if isinstance(key, ColumnClause): </ins><span class="cx"> return BindParamClause(key.name, value, type=key.type) </span><span class="cx"> else: </span><span class="cx"> return BindParamClause(key, value, type=type) </span><span class="lines">@@ -190,7 +194,7 @@ </span><span class="cx"> text - the text of the SQL statement to be created. use :<param> to specify </span><span class="cx"> bind parameters; they will be compiled to their engine-specific format. </span><span class="cx"> </span><del>- engine - the engine to be used for this text query. Alternatively, call the </del><ins>+ engine - an optional engine to be used for this text query. Alternatively, call the </ins><span class="cx"> text() method off the engine directly. </span><span class="cx"> </span><span class="cx"> bindparams - a list of bindparam() instances which can be used to define the </span><span class="lines">@@ -222,15 +226,15 @@ </span><span class="cx"> return CompoundSelect(keyword, *selects, **kwargs) </span><span class="cx"> </span><span class="cx"> def _is_literal(element): </span><del>- return not isinstance(element, ClauseElement) and not isinstance(element, schema.SchemaItem) </del><ins>+ return not isinstance(element, ClauseElement) </ins><span class="cx"> </span><span class="cx"> def is_column(col): </span><del>- return isinstance(col, schema.Column) or isinstance(col, ColumnElement) </del><ins>+ return isinstance(col, ColumnElement) </ins><span class="cx"> </span><del>-class ClauseVisitor(schema.SchemaVisitor): - """builds upon SchemaVisitor to define the visiting of SQL statement elements in - addition to Schema elements.""" - def visit_columnclause(self, column):pass </del><ins>+class ClauseVisitor(object): + """Defines the visiting of ClauseElements.""" + def visit_column(self, column):pass + def visit_table(self, column):pass </ins><span class="cx"> def visit_fromclause(self, fromclause):pass </span><span class="cx"> def visit_bindparam(self, bindparam):pass </span><span class="cx"> def visit_textclause(self, textclause):pass </span><span class="lines">@@ -309,18 +313,6 @@ </span><span class="cx"> </span><span class="cx"> class ClauseElement(object): </span><span class="cx"> """base class for elements of a programmatically constructed SQL expression.""" </span><del>- def hash_key(self): - """returns a string that uniquely identifies the concept this ClauseElement - represents. - - two ClauseElements can have the same value for hash_key() iff they both correspond to - the exact same generated SQL. This allows the hash_key() values of a collection of - ClauseElements to be constructed into a larger identifying string for the purpose of - caching a SQL expression. - - Note that since ClauseElements may be mutable, the hash_key() value is subject to - change if the underlying structure of the ClauseElement changes.""" - raise NotImplementedError(repr(self)) </del><span class="cx"> def _get_from_objects(self): </span><span class="cx"> """returns objects represented in this ClauseElement that should be added to the </span><span class="cx"> FROM list of a query.""" </span><span class="lines">@@ -357,19 +349,24 @@ </span><span class="cx"> return False </span><span class="cx"> </span><span class="cx"> def _find_engine(self): </span><ins>+ """default strategy for locating an engine within the clause element. + relies upon a local engine property, or looks in the "from" objects which + ultimately have to contain Tables or TableClauses. """ </ins><span class="cx"> try: </span><span class="cx"> if self._engine is not None: </span><span class="cx"> return self._engine </span><span class="cx"> except AttributeError: </span><span class="cx"> pass </span><span class="cx"> for f in self._get_from_objects(): </span><ins>+ if f is self: + continue </ins><span class="cx"> engine = f.engine </span><span class="cx"> if engine is not None: </span><span class="cx"> return engine </span><span class="cx"> else: </span><span class="cx"> return None </span><span class="cx"> </span><del>- engine = property(lambda s: s._find_engine()) </del><ins>+ engine = property(lambda s: s._find_engine(), doc="attempts to locate a SQLEngine within this ClauseElement structure, or returns None if none found.") </ins><span class="cx"> </span><span class="cx"> def compile(self, engine = None, parameters = None, typemap=None): </span><span class="cx"> """compiles this SQL expression using its underlying SQLEngine to produce </span><span class="lines">@@ -380,16 +377,13 @@ </span><span class="cx"> engine = self.engine </span><span class="cx"> </span><span class="cx"> if engine is None: </span><del>- raise InvalidRequestError("no SQLEngine could be located within this ClauseElement.") </del><ins>+ import sqlalchemy.ansisql as ansisql + engine = ansisql.engine() </ins><span class="cx"> </span><span class="cx"> return engine.compile(self, parameters=parameters, typemap=typemap) </span><span class="cx"> </span><span class="cx"> def __str__(self): </span><del>- e = self.engine - if e is None: - import sqlalchemy.ansisql as ansisql - e = ansisql.engine() - return str(self.compile(e)) </del><ins>+ return str(self.compile()) </ins><span class="cx"> </span><span class="cx"> def execute(self, *multiparams, **params): </span><span class="cx"> """compiles and executes this SQL expression using its underlying SQLEngine. the </span><span class="lines">@@ -425,6 +419,7 @@ </span><span class="cx"> return not_(self) </span><span class="cx"> </span><span class="cx"> class CompareMixin(object): </span><ins>+ """defines comparison operations for ClauseElements.""" </ins><span class="cx"> def __lt__(self, other): </span><span class="cx"> return self._compare('<', other) </span><span class="cx"> def __le__(self, other): </span><span class="lines">@@ -500,19 +495,15 @@ </span><span class="cx"> </span><span class="cx"> def accept_visitor(self, visitor): </span><span class="cx"> raise NotImplementedError(repr(self)) </span><del>- </del><span class="cx"> def is_selectable(self): </span><span class="cx"> return True </span><del>- </del><span class="cx"> def select(self, whereclauses = None, **params): </span><span class="cx"> return select([self], whereclauses, **params) </span><del>- </del><span class="cx"> def _group_parenthesized(self): </span><span class="cx"> """indicates if this Selectable requires parenthesis when grouped into a compound </span><span class="cx"> statement""" </span><span class="cx"> return True </span><span class="cx"> </span><del>- </del><span class="cx"> class ColumnElement(Selectable, CompareMixin): </span><span class="cx"> """represents a column element within the list of a Selectable's columns. ... [truncated message content] |