sqlalchemy-commits Mailing List for SQLAlchemy (Page 361)
Brought to you by:
zzzeek
You can subscribe to this list here.
2006 |
Jan
|
Feb
(74) |
Mar
(167) |
Apr
(127) |
May
(190) |
Jun
(119) |
Jul
(77) |
Aug
(82) |
Sep
(84) |
Oct
(153) |
Nov
(45) |
Dec
(54) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2007 |
Jan
(109) |
Feb
(80) |
Mar
(110) |
Apr
(106) |
May
(92) |
Jun
(147) |
Jul
(288) |
Aug
(307) |
Sep
(108) |
Oct
(156) |
Nov
(147) |
Dec
(134) |
2008 |
Jan
(126) |
Feb
(91) |
Mar
(184) |
Apr
(208) |
May
(212) |
Jun
(54) |
Jul
(106) |
Aug
(80) |
Sep
(58) |
Oct
(80) |
Nov
(119) |
Dec
(220) |
2009 |
Jan
(202) |
Feb
(50) |
Mar
(70) |
Apr
(46) |
May
(80) |
Jun
(61) |
Jul
(146) |
Aug
(81) |
Sep
(71) |
Oct
(74) |
Nov
(66) |
Dec
(82) |
2010 |
Jan
(112) |
Feb
(169) |
Mar
(235) |
Apr
(77) |
May
(22) |
Jun
(31) |
Jul
(46) |
Aug
(46) |
Sep
(70) |
Oct
(36) |
Nov
(37) |
Dec
(79) |
2011 |
Jan
(46) |
Feb
(54) |
Mar
(65) |
Apr
(73) |
May
(31) |
Jun
(46) |
Jul
(40) |
Aug
(36) |
Sep
(44) |
Oct
(33) |
Nov
(19) |
Dec
(10) |
2012 |
Jan
(60) |
Feb
(37) |
Mar
(35) |
Apr
(28) |
May
(27) |
Jun
(50) |
Jul
(33) |
Aug
(88) |
Sep
(64) |
Oct
(74) |
Nov
(62) |
Dec
(41) |
2013 |
Jan
(30) |
Feb
(37) |
Mar
(39) |
Apr
(52) |
May
(40) |
Jun
(85) |
Jul
(74) |
Aug
(76) |
Sep
(26) |
Oct
(76) |
Nov
(63) |
Dec
(65) |
2014 |
Jan
(68) |
Feb
(82) |
Mar
(87) |
Apr
(24) |
May
(66) |
Jun
(34) |
Jul
(86) |
Aug
(75) |
Sep
(70) |
Oct
(41) |
Nov
(23) |
Dec
(53) |
2015 |
Jan
(40) |
Feb
(39) |
Mar
(69) |
Apr
(64) |
May
(40) |
Jun
(43) |
Jul
(20) |
Aug
(48) |
Sep
(38) |
Oct
(28) |
Nov
(34) |
Dec
(44) |
2016 |
Jan
(82) |
Feb
(49) |
Mar
(25) |
Apr
(21) |
May
(19) |
Jun
(46) |
Jul
(38) |
Aug
(21) |
Sep
(33) |
Oct
(44) |
Nov
(26) |
Dec
(10) |
2017 |
Jan
(52) |
Feb
(18) |
Mar
(61) |
Apr
(43) |
May
(57) |
Jun
(36) |
Jul
(37) |
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: <co...@sq...> - 2006-05-11 19:53:21
|
<!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>[1436] sqlalchemy/branches/schema/doc/build/content/tutorial.txt: threadlocal concept removed</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1436</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-05-11 14:53:11 -0500 (Thu, 11 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>threadlocal concept removed</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemadocbuildcontenttutorialtxt">sqlalchemy/branches/schema/doc/build/content/tutorial.txt</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschemadocbuildcontenttutorialtxt"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/doc/build/content/tutorial.txt (1435 => 1436)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/doc/build/content/tutorial.txt 2006-05-11 15:56:19 UTC (rev 1435) +++ sqlalchemy/branches/schema/doc/build/content/tutorial.txt 2006-05-11 19:53:11 UTC (rev 1436) </span><span class="lines">@@ -47,11 +47,10 @@ </span><span class="cx"> </span><span class="cx"> ### Imports </span><span class="cx"> </span><del>-SQLAlchemy provides the entire namespace of everything you'll need under the module name `sqlalchemy`. For the purposes of this tutorial, we will import its full list of symbols into our own local namespace. We also will be using a *mod* that provides access to thread-managed connection and session objects, which will greatly simplifies our code. A *mod* is a module that augments the core functionality of SQLAlchemy with additional functionality, and only needs to be imported once within an application. </del><ins>+SQLAlchemy provides the entire namespace of everything you'll need under the module name `sqlalchemy`. For the purposes of this tutorial, we will import its full list of symbols into our own local namespace. </ins><span class="cx"> </span><span class="cx"> {python} </span><span class="cx"> >>> from sqlalchemy import * </span><del>- >>> import sqlalchemy.mods.threadlocal </del><span class="cx"> </span><span class="cx"> ### Connecting to the Database </span><span class="cx"> </span><span class="lines">@@ -287,10 +286,10 @@ </span><span class="cx"> </span><span class="cx"> After you create a Mapper, all operations with that Mapper require the usage of an important object called a `Session`. All objects loaded or saved by the Mapper must be *attached* to a `Session` object, which represents a kind of "workspace" of objects that are loaded into memory. A particular object instance can only be attached to one `Session` at a time. </span><span class="cx"> </span><del>-By default, you have to create a `Session` object explicitly before you can load or save objects. But recall that we imported a special *mod* called `threadlocal`, which has made life easier for us by creating a `Session` that is automatically associated with the current thread. So now, lets get a handle to that `Session` and deal with it directly. To locate the `Session` corresponding to the current thread, just use `current_session()`: </del><ins>+By default, you have to create a `Session` object explicitly before you can load or save objects. Theres several ways to manage sessions, but the most straightforward is to just create one, which we will do by saying, `create_session()`: </ins><span class="cx"> </span><span class="cx"> {python} </span><del>- >>> session = current_session() </del><ins>+ >>> session = create_session() </ins><span class="cx"> >>> session # doctest:+ELLIPSIS </span><span class="cx"> <sqlalchemy.orm.session.Session object at 0x...> </span><span class="cx"> </span><span class="lines">@@ -307,7 +306,7 @@ </span><span class="cx"> ['Harry'] </span><span class="cx"> [(User Harry,password:None)] </span><span class="cx"> </span><del>-All querying for objects is performed via an instance of `Query`. The various `select` methods on an instance of `Mapper` also use an underlying `Query` object to perform the operation. A `Query` can be bound to a specific `Session`, or it can also use `current_session()` to locate the session bound to the current thread, if one is available. </del><ins>+All querying for objects is performed via an instance of `Query`. The various `select` methods on an instance of `Mapper` also use an underlying `Query` object to perform the operation. A `Query` is always bound to a specific `Session`. </ins><span class="cx"> </span><span class="cx"> Lets turn off the database echoing for a moment, and try out a few methods on `Query`. Methods that end with the suffix `_by` primarily take keyword arguments which correspond to properties on the object. Other methods take `ClauseElement` objects, which are constructed by using `Column` objects inside of Python expressions, in the same way as we did with our SQL select example in the previous section of this tutorial. Using `ClauseElement` structures to query objects is more verbose but more flexible: </span><span class="cx"> </span><span class="lines">@@ -328,12 +327,13 @@ </span><span class="cx"> </span><span class="cx"> ### Making Changes {@name=changes} </span><span class="cx"> </span><del>-With a little experience in loading objects, lets see what its like to make changes. First, lets create a new user "Ed". We do this by just constructing the new object. The `Mapper` for the `User` class will be called when we create the object, which will then automatically add it to the current thread's Session, if one is available: </del><ins>+With a little experience in loading objects, lets see what its like to make changes. First, lets create a new user "Ed". We do this by just constructing the new object. Then, we just add it to the session: </ins><span class="cx"> </span><span class="cx"> {python} </span><span class="cx"> >>> ed = User() </span><span class="cx"> >>> ed.user_name = 'Ed' </span><span class="cx"> >>> ed.password = 'edspassword' </span><ins>+ >>> session.save(ed) </ins><span class="cx"> >>> ed in session </span><span class="cx"> True </span><span class="cx"> </span><span class="lines">@@ -352,7 +352,7 @@ </span><span class="cx"> >>> mary is mary2 </span><span class="cx"> True </span><span class="cx"> </span><del>-With the identity map, a single `Session` can be relied upon to keep all loaded instances straight, and when a thread-local Session is used, it becomes pretty hard for an application to lose track of the changes made on objects. </del><ins>+With the identity map, a single `Session` can be relied upon to keep all loaded instances straight. </ins><span class="cx"> </span><span class="cx"> As far as the issue of the same object being modified in two different Sessions, that's an issue of concurrency detection; SQLAlchemy does some basic concurrency checks when saving objects, with the option for a stronger check using version ids. See [adv_datamapping](rel:adv_datamapping) for more details. </span><span class="cx"> </span><span class="lines">@@ -375,8 +375,6 @@ </span><span class="cx"> UPDATE users SET password=? WHERE users.user_id = ? </span><span class="cx"> ['harrysnewpassword', 4] </span><span class="cx"> INSERT INTO users (user_name, password) VALUES (?, ?) </span><del>- [None, None] - INSERT INTO users (user_name, password) VALUES (?, ?) </del><span class="cx"> ['Ed', 'edspassword'] </span><span class="cx"> DELETE FROM users WHERE users.user_id = ? </span><span class="cx"> [3] </span><span class="lines">@@ -455,6 +453,7 @@ </span><span class="cx"> ... fred.user_name = 'fred_again' </span><span class="cx"> ... fred.addresses.append(Address('fr...@fr...')) </span><span class="cx"> ... fred.addresses.append(Address('fre...@fr...')) </span><ins>+ ... session.save(fred) </ins><span class="cx"> ... transaction.commit() </span><span class="cx"> ... except: </span><span class="cx"> ... transaction.rollback() </span><span class="lines">@@ -476,9 +475,9 @@ </span><span class="cx"> INSERT INTO users (user_name, password) VALUES (?, ?) </span><span class="cx"> ['fred_again', None] </span><span class="cx"> INSERT INTO email_addresses (email_address, user_id) VALUES (?, ?) </span><del>- ['fr...@fr...', 7] </del><ins>+ ['fr...@fr...', 6] </ins><span class="cx"> INSERT INTO email_addresses (email_address, user_id) VALUES (?, ?) </span><del>- ['fre...@fr...', 7] </del><ins>+ ['fre...@fr...', 6] </ins><span class="cx"> COMMIT </span><span class="cx"> </span><span class="cx"> Main documentation: [unitofwork](rel:unitofwork) </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-05-11 15:56:32
|
<!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>[1435] sqlalchemy/branches/schema/test: added auto-rollback in pool return connection, so that locks can be cleared when connection is returned</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1435</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-05-11 10:56:19 -0500 (Thu, 11 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>added auto-rollback in pool return connection, so that locks can be cleared when connection is returned added transaction unittest module</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemalibsqlalchemypoolpy">sqlalchemy/branches/schema/lib/sqlalchemy/pool.py</a></li> <li><a href="#sqlalchemybranchesschematestalltestspy">sqlalchemy/branches/schema/test/alltests.py</a></li> </ul> <h3>Added Paths</h3> <ul> <li><a href="#sqlalchemybranchesschematesttransactionpy">sqlalchemy/branches/schema/test/transaction.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschemalibsqlalchemypoolpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/pool.py (1434 => 1435)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/pool.py 2006-05-10 23:46:20 UTC (rev 1434) +++ sqlalchemy/branches/schema/lib/sqlalchemy/pool.py 2006-05-11 15:56:19 UTC (rev 1435) </span><span class="lines">@@ -137,6 +137,7 @@ </span><span class="cx"> def invalidate(self): </span><span class="cx"> if self.pool.echo: </span><span class="cx"> self.pool.log("Invalidate connection %s" % repr(self.connection)) </span><ins>+ self.connection.rollback() </ins><span class="cx"> self.connection = None </span><span class="cx"> self.pool.return_invalid() </span><span class="cx"> def cursor(self): </span><span class="lines">@@ -158,6 +159,7 @@ </span><span class="cx"> if self.connection is not None: </span><span class="cx"> if self.pool.echo: </span><span class="cx"> self.pool.log("Connection %s being returned to pool" % repr(self.connection)) </span><ins>+ self.connection.rollback() </ins><span class="cx"> self.pool.return_conn(self) </span><span class="cx"> self.pool = None </span><span class="cx"> self.connection = None </span></span></pre></div> <a id="sqlalchemybranchesschematestalltestspy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/test/alltests.py (1434 => 1435)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/test/alltests.py 2006-05-10 23:46:20 UTC (rev 1434) +++ sqlalchemy/branches/schema/test/alltests.py 2006-05-11 15:56:19 UTC (rev 1435) </span><span class="lines">@@ -15,6 +15,7 @@ </span><span class="cx"> # connectivity, execution </span><span class="cx"> 'pool', </span><span class="cx"> 'engine', </span><ins>+ 'transaction', </ins><span class="cx"> </span><span class="cx"> # schema/tables </span><span class="cx"> 'reflection', </span></span></pre></div> <a id="sqlalchemybranchesschematesttransactionpy"></a> <div class="addfile"><h4>Added: sqlalchemy/branches/schema/test/transaction.py (1434 => 1435)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/test/transaction.py 2006-05-10 23:46:20 UTC (rev 1434) +++ sqlalchemy/branches/schema/test/transaction.py 2006-05-11 15:56:19 UTC (rev 1435) </span><span class="lines">@@ -0,0 +1,63 @@ </span><ins>+ +import testbase +import unittest, sys, datetime +import tables +db = testbase.db +from sqlalchemy import * + +class TransactionTest(testbase.PersistTest): + def setUpAll(self): + global users, metadata + metadata = MetaData() + users = Table('query_users', metadata, + Column('user_id', INT, primary_key = True), + Column('user_name', VARCHAR(20)), + ) + users.create(testbase.db) + + def tearDown(self): + testbase.db.connect().execute(users.delete()) + def tearDownAll(self): + users.drop(testbase.db) + + @testbase.unsupported('mysql') + def testrollback(self): + """test a basic rollback""" + connection = testbase.db.connect() + transaction = connection.begin() + connection.execute(users.insert(), user_id=1, user_name='user1') + connection.execute(users.insert(), user_id=2, user_name='user2') + connection.execute(users.insert(), user_id=3, user_name='user3') + transaction.rollback() + + result = connection.execute("select * from query_users") + assert len(result.fetchall()) == 0 + connection.close() + +class AutoRollbackTest(testbase.PersistTest): + def setUpAll(self): + global metadata + metadata = MetaData() + + def tearDownAll(self): + metadata.drop_all(testbase.db) + + def testrollback_deadlock(self): + """test that returning connections to the pool clears any object locks.""" + conn1 = testbase.db.connect() + conn2 = testbase.db.connect() + users = Table('deadlock_users', metadata, + Column('user_id', INT, primary_key = True), + Column('user_name', VARCHAR(20)), + ) + users.create(conn1) + conn1.execute("select * from deadlock_users") + conn1.close() + # without auto-rollback in the connection pool's return() logic, this deadlocks in Postgres, + # because conn1 is returned to the pool but still has a lock on "deadlock_users" + # comment out the rollback in pool/ConnectionFairy._close() to see ! + users.drop(conn2) + conn2.close() + +if __name__ == "__main__": + testbase.main() </ins></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-05-10 23:46:30
|
<!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>[1434] sqlalchemy/branches/schema/test/selectresults.py: added a test for select_by, put thread-local adapter in</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1434</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-05-10 18:46:20 -0500 (Wed, 10 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>added a test for select_by, put thread-local adapter in</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesschematestselectresultspy">sqlalchemy/branches/schema/test/selectresults.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschematestselectresultspy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/test/selectresults.py (1433 => 1434)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/test/selectresults.py 2006-05-10 20:26:53 UTC (rev 1433) +++ sqlalchemy/branches/schema/test/selectresults.py 2006-05-10 23:46:20 UTC (rev 1434) </span><span class="lines">@@ -10,24 +10,33 @@ </span><span class="cx"> </span><span class="cx"> class SelectResultsTest(PersistTest): </span><span class="cx"> def setUpAll(self): </span><ins>+ self.install_threadlocal() </ins><span class="cx"> global foo </span><span class="cx"> foo = Table('foo', testbase.db, </span><span class="cx"> Column('id', Integer, Sequence('foo_id_seq'), primary_key=True), </span><del>- Column('bar', Integer)) </del><ins>+ Column('bar', Integer), + Column('range', Integer)) </ins><span class="cx"> </span><span class="cx"> assign_mapper(Foo, foo, extension=SelectResultsExt()) </span><span class="cx"> foo.create() </span><span class="cx"> for i in range(100): </span><del>- Foo(bar=i) </del><ins>+ Foo(bar=i, range=i%10) </ins><span class="cx"> objectstore.flush() </span><span class="cx"> </span><span class="cx"> def setUp(self): </span><del>- self.orig = Foo.mapper.select_whereclause() - self.res = Foo.select() </del><ins>+ self.query = Foo.mapper.query() + self.orig = self.query.select_whereclause() + self.res = self.query.select() </ins><span class="cx"> </span><span class="cx"> def tearDownAll(self): </span><span class="cx"> global foo </span><span class="cx"> foo.drop() </span><ins>+ self.uninstall_threadlocal() + + def test_selectby(self): + res = self.query.select_by(range=5) + assert res.order_by([Foo.c.bar])[0].bar == 5 + assert res.order_by([desc(Foo.c.bar)])[0].bar == 95 </ins><span class="cx"> </span><span class="cx"> def test_slice(self): </span><span class="cx"> assert self.res[1] == self.orig[1] </span></span></pre> </div> </div> </body> </html> |
<!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>[1433] sqlalchemy/branches/schema/test/mapper.py: added a unit test to insure that using mapper.options to create an eager load of a many-to-many relation works</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1433</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-05-10 15:26:53 -0500 (Wed, 10 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>added a unit test to insure that using mapper.options to create an eager load of a many-to-many relation works</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesschematestmapperpy">sqlalchemy/branches/schema/test/mapper.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschematestmapperpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/test/mapper.py (1432 => 1433)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/test/mapper.py 2006-05-09 22:17:58 UTC (rev 1432) +++ sqlalchemy/branches/schema/test/mapper.py 2006-05-10 20:26:53 UTC (rev 1433) </span><span class="lines">@@ -855,6 +855,27 @@ </span><span class="cx"> {'item_id' : 2, 'keywords' : (Keyword, [{'keyword_id' : 2}, {'keyword_id' : 5}, {'keyword_id' : 7}])}, </span><span class="cx"> ) </span><span class="cx"> </span><ins>+ def testmanytomanyoptions(self): + items = orderitems + + m = mapper(Item, items, properties = dict( + keywords = relation(mapper(Keyword, keywords), itemkeywords, lazy=True, order_by=[keywords.c.keyword_id]), + )) + m2 = m.options(eagerload('keywords')) + q = create_session().query(m2) + def go(): + l = q.select() + self.assert_result(l, Item, *item_keyword_result) + self.assert_sql_count(db, go, 1) + + def go(): + l = q.select(and_(keywords.c.name == 'red', keywords.c.keyword_id == itemkeywords.c.keyword_id, items.c.item_id==itemkeywords.c.item_id)) + self.assert_result(l, Item, + {'item_id' : 1, 'keywords' : (Keyword, [{'keyword_id' : 2}, {'keyword_id' : 4}, {'keyword_id' : 6}])}, + {'item_id' : 2, 'keywords' : (Keyword, [{'keyword_id' : 2}, {'keyword_id' : 5}, {'keyword_id' : 7}])}, + ) + self.assert_sql_count(db, go, 1) + </ins><span class="cx"> def testoneandmany(self): </span><span class="cx"> """tests eager load for a parent object with a child object that </span><span class="cx"> contains a many-to-many relationship to a third object.""" </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-05-09 22:18:09
|
<!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>[1432] sqlalchemy/branches/schema/test/mapper.py: added a select unit test</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1432</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-05-09 17:17:58 -0500 (Tue, 09 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>added a select unit test</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesschematestmapperpy">sqlalchemy/branches/schema/test/mapper.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschematestmapperpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/test/mapper.py (1431 => 1432)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/test/mapper.py 2006-05-09 01:20:33 UTC (rev 1431) +++ sqlalchemy/branches/schema/test/mapper.py 2006-05-09 22:17:58 UTC (rev 1432) </span><span class="lines">@@ -522,6 +522,21 @@ </span><span class="cx"> {'user_id' : 9, 'addresses' : (Address, [])} </span><span class="cx"> ) </span><span class="cx"> </span><ins>+ def testorderby_select(self): + """tests that a regular mapper select on a single table can order by a relation to a second table""" + m = mapper(Address, addresses) + + m = mapper(User, users, properties = dict( + addresses = relation(m, lazy = True), + )) + q = create_session().query(m) + l = q.select(users.c.user_id==addresses.c.user_id, order_by=addresses.c.email_address) + + self.assert_result(l, User, + {'user_id' : 8, 'addresses' : (Address, [{'email_address':'ed...@wo...'}, {'email_address':'ed...@be...'}, {'email_address':'ed...@la...'}, ])}, + {'user_id' : 7, 'addresses' : (Address, [{'email_address' : 'ja...@be...'}])}, + ) + </ins><span class="cx"> def testorderby_desc(self): </span><span class="cx"> m = mapper(Address, addresses) </span><span class="cx"> </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-05-09 01:20:42
|
<!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>[1431] sqlalchemy/branches/schema/test: small edits</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1431</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-05-08 20:20:33 -0500 (Mon, 08 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>small edits</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemalibsqlalchemyormmapperpy">sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py</a></li> <li><a href="#sqlalchemybranchesschematestselectablepy">sqlalchemy/branches/schema/test/selectable.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschemalibsqlalchemyormmapperpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py (1430 => 1431)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py 2006-05-09 01:20:08 UTC (rev 1430) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py 2006-05-09 01:20:33 UTC (rev 1431) </span><span class="lines">@@ -466,7 +466,7 @@ </span><span class="cx"> def identity_key(self, primary_key): </span><span class="cx"> """returns the instance key for the given identity value. this is a global tracking object used by the Session, and is usually available off a mapped object as instance._instance_key.""" </span><span class="cx"> return sessionlib.get_id_key(util.to_list(primary_key), self.class_, self.entity_name) </span><del>- </del><ins>+ </ins><span class="cx"> def instance_key(self, instance): </span><span class="cx"> """returns the instance key for the given instance. this is a global tracking object used by the Session, and is usually available off a mapped object as instance._instance_key.""" </span><span class="cx"> return self.identity_key(self.identity(instance)) </span><span class="lines">@@ -486,8 +486,7 @@ </span><span class="cx"> mapper.__dict__.update(kwargs) </span><span class="cx"> mapper.props = self.props.copy() </span><span class="cx"> return mapper </span><del>- - </del><ins>+ </ins><span class="cx"> def options(self, *options, **kwargs): </span><span class="cx"> """uses this mapper as a prototype for a new mapper with different behavior. </span><span class="cx"> *options is a list of options directives, which include eagerload(), lazyload(), and noload()""" </span><span class="lines">@@ -835,9 +834,7 @@ </span><span class="cx"> </span><span class="cx"> def translate_row(self, tomapper, row): </span><span class="cx"> """attempts to take a row and translate its values to a row that can </span><del>- be understood by another mapper. breaks the column references down to their - bare keynames to accomplish this. So far this works for the various polymorphic - examples.""" </del><ins>+ be understood by another mapper.""" </ins><span class="cx"> newrow = util.DictDecorator(row) </span><span class="cx"> for c in tomapper.select_table.c: </span><span class="cx"> c2 = self.select_table.corresponding_column(c) </span><span class="lines">@@ -847,7 +844,6 @@ </span><span class="cx"> def populate_instance(self, session, instance, row, identitykey, imap, isnew, frommapper=None): </span><span class="cx"> if frommapper is not None: </span><span class="cx"> row = frommapper.translate_row(self, row) </span><del>- </del><span class="cx"> for prop in self.props.values(): </span><span class="cx"> prop.execute(session, instance, row, identitykey, imap, isnew) </span><span class="cx"> </span></span></pre></div> <a id="sqlalchemybranchesschematestselectablepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/test/selectable.py (1430 => 1431)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/test/selectable.py 2006-05-09 01:20:08 UTC (rev 1430) +++ sqlalchemy/branches/schema/test/selectable.py 2006-05-09 01:20:33 UTC (rev 1431) </span><span class="lines">@@ -59,11 +59,10 @@ </span><span class="cx"> ).alias('analias') </span><span class="cx"> s1 = table.select(use_labels=True) </span><span class="cx"> s2 = table2.select(use_labels=True) </span><del>- print ["%d %s" % (id(c),c.key) for c in u.c] -# c = u.corresponding_column(s1.c.table1_col2) - print "%d %s" % (id(c), c.key) </del><span class="cx"> assert u.corresponding_column(s1.c.table1_col2) is u.c.col2 </span><span class="cx"> assert u.corresponding_column(s2.c.table2_col2) is u.c.col2 </span><ins>+ assert u.corresponding_column(s2.c.table2_coly) is u.c.coly + assert s2.corresponding_column(u.c.coly) is s2.c.table2_coly </ins><span class="cx"> </span><span class="cx"> def testselectunion(self): </span><span class="cx"> # like testaliasunion, but off a Select off the union. </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-05-09 01:20:17
|
<!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>[1430] sqlalchemy/branches/schema/doc/build/content: a few edits</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1430</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-05-08 20:20:08 -0500 (Mon, 08 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>a few edits</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemadocbuildcontentmetadatatxt">sqlalchemy/branches/schema/doc/build/content/metadata.txt</a></li> <li><a href="#sqlalchemybranchesschemadocbuildcontenttutorialtxt">sqlalchemy/branches/schema/doc/build/content/tutorial.txt</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschemadocbuildcontentmetadatatxt"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/doc/build/content/metadata.txt (1429 => 1430)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/doc/build/content/metadata.txt 2006-05-08 22:10:00 UTC (rev 1429) +++ sqlalchemy/branches/schema/doc/build/content/metadata.txt 2006-05-09 01:20:08 UTC (rev 1430) </span><span class="lines">@@ -117,6 +117,8 @@ </span><span class="cx"> </span><span class="cx"> meta.connect('mysql://user@host/dsn') # create a new Engine and connect </span><span class="cx"> </span><ins>+`DynamicMetaData` is ideal for applications that need to use the same set of `Tables` for many different database connections in the same process, such as a CherryPy web application which handles multiple application instances in one process. + </ins><span class="cx"> #### Reflecting Tables </span><span class="cx"> </span><span class="cx"> Once you have a `BoundMetaData` or a connected `DynamicMetaData`, you can create `Table` objects without specifying their columns, just their names, using `autoload=True`: </span></span></pre></div> <a id="sqlalchemybranchesschemadocbuildcontenttutorialtxt"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/doc/build/content/tutorial.txt (1429 => 1430)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/doc/build/content/tutorial.txt 2006-05-08 22:10:00 UTC (rev 1429) +++ sqlalchemy/branches/schema/doc/build/content/tutorial.txt 2006-05-09 01:20:08 UTC (rev 1430) </span><span class="lines">@@ -80,20 +80,10 @@ </span><span class="cx"> {python} </span><span class="cx"> >>> metadata = BoundMetaData('sqlite:///tutorial.db') </span><span class="cx"> </span><del>-When creating MetaData objects that are bound to Engines, all objects within the MetaData or which are derived from it are similarly bound to that engine; this includes tables and SQL statement constructs. A SQL construct that is bound to an Engine supports "connectionless execution", that is, each object knows how to retrieve connections and use them automatically for its own execution, without you having to worry about it. However, note that the "binding" of schema and SQL constructs to engines is **entirely optional**. SQLAlchemy includes full support for explicit Connections used with schema and SQL constructs that are entirely unbound to any Engine. </del><ins>+Now, when we tell "metadata" about the tables in our database, we can issue CREATE statements for those tables, as well as create and execute SQL statements derived from them, without needing to open or close any connections; that will be all done automatically. Note that this feature is **entirely optional**. SQLAlchemy includes full support for explicit Connections used with schema and SQL constructs that are entirely unbound to any Engine. </ins><span class="cx"> </span><del>-For the purposes of this tutorial, we will stick with "bound" objects. There is also a more flexible "dynamic" metadata object that supports runtime binding to multiple engines: </del><ins>+For the purposes of this tutorial, we will stick with "bound" objects, as it makes the code simpler and easier to read. </ins><span class="cx"> </span><del>- {python} - >>> dynamic = DynamicMetaData() # create a Dynamic metadata object - >>> dynamic.connect('sqlite:///:memory:') # connect it to SQLite - >>> dynamic.connect('postgres://scott:tiger@localhost/mydb') # connect it to PostGres - - >>> myengine = create_engine('mysql://127.0.0.1') - >>> dynamic.connect(myengine) # connect to an externally-defined engine - -The `DynamicMetaData` object binds to different engines on a thread local basis. This means that one thread of your application can be connected to one database, while another is connected to a different database. The `DynamicMetaData` object also keeps a reference to each bound engine internally, so that each connection string is only initialized once. - </del><span class="cx"> ### Creating a Table {@name=table} </span><span class="cx"> </span><span class="cx"> With `metadata` as our established home for tables, lets make a Table for it: </span><span class="lines">@@ -389,7 +379,7 @@ </span><span class="cx"> INSERT INTO users (user_name, password) VALUES (?, ?) </span><span class="cx"> ['Ed', 'edspassword'] </span><span class="cx"> DELETE FROM users WHERE users.user_id = ? </span><del>- [[3]] </del><ins>+ [3] </ins><span class="cx"> COMMIT </span><span class="cx"> </span><span class="cx"> ### Relationships </span><span class="lines">@@ -431,7 +421,7 @@ </span><span class="cx"> >>> print [a for a in mary.addresses] </span><span class="cx"> SELECT email_addresses.user_id AS email_addresses_user_id, email_addresses.address_id AS email_addresses_address_id, email_addresses.email_address AS email_addresses_email_address </span><span class="cx"> FROM email_addresses </span><del>- WHERE email_addresses.user_id = ? ORDER BY email_addresses.oid </del><ins>+ WHERE ? = email_addresses.user_id ORDER BY email_addresses.oid </ins><span class="cx"> [1] </span><span class="cx"> [(Address ma...@ma...)] </span><span class="cx"> </span><span class="lines">@@ -476,7 +466,7 @@ </span><span class="cx"> ['Ed', 'Harry', 'Mary'] </span><span class="cx"> SELECT email_addresses.user_id AS email_addresses_user_id, email_addresses.address_id AS email_addresses_address_id, email_addresses.email_address AS email_addresses_email_address </span><span class="cx"> FROM email_addresses </span><del>- WHERE email_addresses.user_id = ? ORDER BY email_addresses.oid </del><ins>+ WHERE ? = email_addresses.user_id ORDER BY email_addresses.oid </ins><span class="cx"> [4] </span><span class="cx"> UPDATE email_addresses SET user_id=? WHERE email_addresses.address_id = ? </span><span class="cx"> [None, 3] </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-05-08 22:10:17
|
<!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>[1429] sqlalchemy/branches/schema/test: - Fixed ProxyEngine tests (use MetaData, new Session API, etc).</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1429</dd> <dt>Author</dt> <dd>niemeyer</dd> <dt>Date</dt> <dd>2006-05-08 17:10:00 -0500 (Mon, 08 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>- Fixed ProxyEngine tests (use MetaData, new Session API, etc). - Removed unneeded imports in sqlalchemy.ext.proxy. - Removed execute_compiled() and compiler() methods from BaseProxyEngine. There's no need for them to be special cased.</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemalibsqlalchemyextproxypy">sqlalchemy/branches/schema/lib/sqlalchemy/ext/proxy.py</a></li> <li><a href="#sqlalchemybranchesschematestproxy_enginepy">sqlalchemy/branches/schema/test/proxy_engine.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschemalibsqlalchemyextproxypy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/ext/proxy.py (1428 => 1429)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/ext/proxy.py 2006-05-08 19:00:51 UTC (rev 1428) +++ sqlalchemy/branches/schema/lib/sqlalchemy/ext/proxy.py 2006-05-08 22:10:00 UTC (rev 1429) </span><span class="lines">@@ -5,15 +5,10 @@ </span><span class="cx"> </span><span class="cx"> from sqlalchemy import sql </span><span class="cx"> from sqlalchemy.engine import create_engine </span><del>-from sqlalchemy.types import TypeEngine -import sqlalchemy.schema as schema -import thread, weakref </del><span class="cx"> </span><span class="cx"> </span><span class="cx"> class BaseProxyEngine(sql.Engine): </span><del>- ''' - Basis for all proxy engines - ''' </del><ins>+ """Basis for all proxy engines.""" </ins><span class="cx"> </span><span class="cx"> def get_engine(self): </span><span class="cx"> raise NotImplementedError </span><span class="lines">@@ -23,28 +18,18 @@ </span><span class="cx"> </span><span class="cx"> engine = property(lambda s:s.get_engine(), lambda s,e:s.set_engine(e)) </span><span class="cx"> </span><del>- 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 hash_key(self): - return "%s(%s)" % (self.__class__.__name__, id(self)) - </del><span class="cx"> def __getattr__(self, attr): </span><span class="cx"> # call get_engine() to give subclasses a chance to change </span><span class="cx"> # connection establishment behavior </span><del>- e= self.get_engine() </del><ins>+ e = self.get_engine() </ins><span class="cx"> if e is not None: </span><span class="cx"> return getattr(e, attr) </span><del>- raise AttributeError('No connection established in ProxyEngine: ' - ' no access to %s' % attr) </del><ins>+ raise AttributeError("No connection established in ProxyEngine: " + " no access to %s" % attr) </ins><span class="cx"> </span><span class="cx"> </span><span class="cx"> class AutoConnectEngine(BaseProxyEngine): </span><del>- ''' - An SQLEngine proxy that automatically connects when necessary. - ''' </del><ins>+ """An SQLEngine proxy that automatically connects when necessary.""" </ins><span class="cx"> </span><span class="cx"> def __init__(self, dburi, **kwargs): </span><span class="cx"> BaseProxyEngine.__init__(self) </span><span class="lines">@@ -62,13 +47,11 @@ </span><span class="cx"> return self._engine </span><span class="cx"> </span><span class="cx"> </span><del>- </del><span class="cx"> class ProxyEngine(BaseProxyEngine): </span><ins>+ """Engine proxy for lazy and late initialization. + + This engine will delegate access to a real engine set with connect(). </ins><span class="cx"> """ </span><del>- SQLEngine proxy. Supports lazy and late initialization by - delegating to a real engine (set with connect()), and using proxy - classes for TypeEngine. - """ </del><span class="cx"> </span><span class="cx"> def __init__(self, **kwargs): </span><span class="cx"> BaseProxyEngine.__init__(self) </span><span class="lines">@@ -79,8 +62,8 @@ </span><span class="cx"> self.kwargs = kwargs </span><span class="cx"> </span><span class="cx"> def connect(self, *args, **kwargs): </span><del>- """Establish connection to a real engine. - """ </del><ins>+ """Establish connection to a real engine.""" + </ins><span class="cx"> kwargs.update(self.kwargs) </span><span class="cx"> if not kwargs: </span><span class="cx"> key = repr(args) </span><span class="lines">@@ -100,7 +83,7 @@ </span><span class="cx"> </span><span class="cx"> def get_engine(self): </span><span class="cx"> if self.storage.engine is None: </span><del>- raise AttributeError('No connection established') </del><ins>+ raise AttributeError("No connection established") </ins><span class="cx"> return self.storage.engine </span><span class="cx"> </span><span class="cx"> def set_engine(self, engine): </span></span></pre></div> <a id="sqlalchemybranchesschematestproxy_enginepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/test/proxy_engine.py (1428 => 1429)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/test/proxy_engine.py 2006-05-08 19:00:51 UTC (rev 1428) +++ sqlalchemy/branches/schema/test/proxy_engine.py 2006-05-08 22:10:00 UTC (rev 1429) </span><span class="lines">@@ -1,3 +1,5 @@ </span><ins>+import os + </ins><span class="cx"> from sqlalchemy import * </span><span class="cx"> from sqlalchemy.ext.proxy import ProxyEngine </span><span class="cx"> </span><span class="lines">@@ -3,5 +5,4 @@ </span><span class="cx"> from testbase import PersistTest </span><span class="cx"> import testbase </span><del>-import os </del><span class="cx"> </span><span class="cx"> # </span><span class="lines">@@ -12,7 +13,9 @@ </span><span class="cx"> </span><span class="cx"> </span><span class="cx"> module_engine = ProxyEngine(echo=testbase.echo) </span><del>-users = Table('users', module_engine, </del><ins>+module_metadata = MetaData() + +users = Table('users', module_metadata, </ins><span class="cx"> Column('user_id', Integer, primary_key=True), </span><span class="cx"> Column('user_name', String(16)), </span><span class="cx"> Column('password', String(20)) </span><span class="lines">@@ -21,10 +24,13 @@ </span><span class="cx"> class User(object): </span><span class="cx"> pass </span><span class="cx"> </span><ins>+User.mapper = mapper(User, users) </ins><span class="cx"> </span><ins>+ </ins><span class="cx"> class ConstructTest(PersistTest): </span><span class="cx"> """tests that we can build SQL constructs without engine-specific parameters, particulary </span><span class="cx"> oid_column, being needed, as the proxy engine is usually not connected yet.""" </span><ins>+ </ins><span class="cx"> def test_join(self): </span><span class="cx"> engine = ProxyEngine() </span><span class="cx"> t = Table('table1', engine, </span><span class="lines">@@ -33,47 +39,46 @@ </span><span class="cx"> Column('col2', Integer, ForeignKey('table1.col1'))) </span><span class="cx"> j = join(t, t2) </span><span class="cx"> </span><ins>+ </ins><span class="cx"> class ProxyEngineTest1(PersistTest): </span><span class="cx"> </span><del>- def setUp(self): - clear_mappers() - objectstore.clear() - </del><span class="cx"> def test_engine_connect(self): </span><span class="cx"> # connect to a real engine </span><span class="cx"> module_engine.connect(testbase.db_uri) </span><del>- users.create() - assign_mapper(User, users) </del><ins>+ module_metadata.create_all(module_engine) + + session = create_session(bind_to=module_engine) </ins><span class="cx"> try: </span><del>- trans = objectstore.begin() </del><span class="cx"> </span><span class="cx"> user = User() </span><span class="cx"> user.user_name='fred' </span><span class="cx"> user.password='*' </span><del>- trans.commit() </del><span class="cx"> </span><ins>+ session.save(user) + session.flush() + + query = session.query(User) + </ins><span class="cx"> # select </span><del>- sqluser = User.select_by(user_name='fred')[0] </del><ins>+ sqluser = query.select_by(user_name='fred')[0] </ins><span class="cx"> assert sqluser.user_name == 'fred' </span><span class="cx"> </span><span class="cx"> # modify </span><span class="cx"> sqluser.user_name = 'fred jones' </span><span class="cx"> </span><del>- # commit - saves everything that changed - objectstore.commit() </del><ins>+ # flush - saves everything that changed + session.flush() </ins><span class="cx"> </span><del>- allusers = [ user.user_name for user in User.select() ] - assert allusers == [ 'fred jones' ] </del><ins>+ allusers = [ user.user_name for user in query.select() ] + assert allusers == ['fred jones'] + </ins><span class="cx"> finally: </span><del>- users.drop() </del><ins>+ module_metadata.drop_all(module_engine) </ins><span class="cx"> </span><ins>+ </ins><span class="cx"> class ThreadProxyTest(PersistTest): </span><del>- def setUp(self): - assign_mapper(User, users) - def tearDown(self): - clear_mappers() </del><ins>+ </ins><span class="cx"> def tearDownAll(self): </span><del>- pass </del><span class="cx"> os.remove('threadtesta.db') </span><span class="cx"> os.remove('threadtestb.db') </span><span class="cx"> </span><span class="lines">@@ -92,23 +97,26 @@ </span><span class="cx"> </span><span class="cx"> try: </span><span class="cx"> module_engine.connect(db_uri) </span><del>- users.create() </del><ins>+ module_metadata.create_all(module_engine) </ins><span class="cx"> try: </span><del>- trans = objectstore.begin() </del><ins>+ session = create_session(bind_to=module_engine) </ins><span class="cx"> </span><del>- all = User.select()[:] </del><ins>+ query = session.query(User) + + all = list(query.select()) </ins><span class="cx"> assert all == [] </span><span class="cx"> </span><span class="cx"> u = User() </span><span class="cx"> u.user_name = uname </span><span class="cx"> u.password = 'whatever' </span><del>- trans.commit() </del><span class="cx"> </span><del>- names = [ us.user_name for us in User.select() ] - assert names == [ uname ] </del><ins>+ session.save(u) + session.flush() + + names = [u.user_name for u in query.select()] + assert names == [uname] </ins><span class="cx"> finally: </span><del>- users.drop() - module_engine.dispose() </del><ins>+ module_metadata.drop_all(module_engine) </ins><span class="cx"> except Exception, e: </span><span class="cx"> import traceback </span><span class="cx"> traceback.print_exc() </span><span class="lines">@@ -119,8 +127,8 @@ </span><span class="cx"> </span><span class="cx"> # NOTE: I'm not sure how to give the test runner the option to </span><span class="cx"> # override these uris, or how to safely clear them after test runs </span><del>- a = Thread(target=run('sqlite://filename=threadtesta.db', 'jim', qa)) - b = Thread(target=run('sqlite://filename=threadtestb.db', 'joe', qb)) </del><ins>+ a = Thread(target=run('sqlite:///threadtesta.db', 'jim', qa)) + b = Thread(target=run('sqlite:///threadtestb.db', 'joe', qb)) </ins><span class="cx"> </span><span class="cx"> a.start() </span><span class="cx"> b.start() </span><span class="lines">@@ -134,12 +142,9 @@ </span><span class="cx"> if res != False: </span><span class="cx"> raise res </span><span class="cx"> </span><ins>+ </ins><span class="cx"> class ProxyEngineTest2(PersistTest): </span><span class="cx"> </span><del>- def setUp(self): - clear_mappers() - objectstore.clear() - </del><span class="cx"> def test_table_singleton_a(self): </span><span class="cx"> """set up for table singleton check </span><span class="cx"> """ </span><span class="lines">@@ -153,9 +158,10 @@ </span><span class="cx"> Column('cat_name', String)) </span><span class="cx"> </span><span class="cx"> engine.connect(testbase.db_uri) </span><del>- cats.create() - cats.drop() </del><span class="cx"> </span><ins>+ cats.create(engine) + cats.drop(engine) + </ins><span class="cx"> ProxyEngineTest2.cats_table_a = cats </span><span class="cx"> assert isinstance(cats, Table) </span><span class="cx"> </span><span class="lines">@@ -179,141 +185,8 @@ </span><span class="cx"> # this will fail because the old reference's local storage will </span><span class="cx"> # not have the default attributes </span><span class="cx"> engine.connect(testbase.db_uri) </span><del>- cats.create() - cats.drop() </del><ins>+ cats.create(engine) + cats.drop(engine) </ins><span class="cx"> </span><del>- def test_type_engine_caching(self): - from sqlalchemy.engine import SQLEngine - import sqlalchemy.types as sqltypes - - class EngineA(SQLEngine): - def __init__(self): - pass - - def hash_key(self): - return 'a' - - def type_descriptor(self, typeobj): - if isinstance(typeobj, types.Integer): - return TypeEngineX2() - else: - return TypeEngineSTR() - - class EngineB(SQLEngine): - def __init__(self): - pass - - def hash_key(self): - return 'b' - - def type_descriptor(self, typeobj): - return TypeEngineMonkey() - - class TypeEngineX2(sqltypes.TypeEngine): - def convert_bind_param(self, value, engine): - return value * 2 - - class TypeEngineSTR(sqltypes.TypeEngine): - def convert_bind_param(self, value, engine): - return repr(str(value)) - - class TypeEngineMonkey(sqltypes.TypeEngine): - def convert_bind_param(self, value, engine): - return 'monkey' - - engine = ProxyEngine() - engine.storage.engine = EngineA() - - a = sqltypes.Integer().engine_impl(engine) - assert a.convert_bind_param(12, engine) == 24 - assert a.convert_bind_param([1,2,3], engine) == [1, 2, 3, 1, 2, 3] - - a2 = sqltypes.String().engine_impl(engine) - assert a2.convert_bind_param(12, engine) == "'12'" - assert a2.convert_bind_param([1,2,3], engine) == "'[1, 2, 3]'" - - engine.storage.engine = EngineB() - b = sqltypes.Integer().engine_impl(engine) - assert b.convert_bind_param(12, engine) == 'monkey' - assert b.convert_bind_param([1,2,3], engine) == 'monkey' - - - def test_type_engine_autoincrement(self): - engine = ProxyEngine() - dogs = Table('dogs', engine, - Column('dog_id', Integer, primary_key=True), - Column('breed', String), - Column('name', String)) - - class Dog(object): - pass - - assign_mapper(Dog, dogs) - - engine.connect(testbase.db_uri) - dogs.create() - try: - spot = Dog() - spot.breed = 'beagle' - spot.name = 'Spot' - - rover = Dog() - rover.breed = 'spaniel' - rover.name = 'Rover' - - objectstore.commit() - - assert spot.dog_id > 0, "Spot did not get an id" - assert rover.dog_id != spot.dog_id - finally: - dogs.drop() - - def test_type_proxy_schema_gen(self): - from sqlalchemy.databases.postgres import PGSchemaGenerator - - engine = ProxyEngine() - lizards = Table('lizards', engine, - Column('id', Integer, primary_key=True), - Column('name', String)) - - # this doesn't really CONNECT to pg, just establishes pg as the - # actual engine so that we can determine that it gets the right - # answer - engine.connect('postgres://database=test&port=5432&host=127.0.0.1&user=scott&password=tiger') - - sg = PGSchemaGenerator(engine) - id_spec = sg.get_column_specification(lizards.c.id) - assert id_spec == 'id SERIAL NOT NULL PRIMARY KEY' - - </del><span class="cx"> if __name__ == "__main__": </span><span class="cx"> testbase.main() </span><del>- - - - - - - - - - - - - - - - - - - - - - - - - - - - - </del></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-05-08 19:01:26
|
<!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>[1428] sqlalchemy/branches/schema/lib/sqlalchemy: assorted cleanuppage</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1428</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-05-08 14:00:51 -0500 (Mon, 08 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>assorted cleanuppage</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemalibsqlalchemyormmapperpy">sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemysqlpy">sqlalchemy/branches/schema/lib/sqlalchemy/sql.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschemalibsqlalchemyormmapperpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py (1427 => 1428)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py 2006-05-08 18:43:43 UTC (rev 1427) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py 2006-05-08 19:00:51 UTC (rev 1428) </span><span class="lines">@@ -541,7 +541,6 @@ </span><span class="cx"> """called by a UnitOfWork object to save objects, which involves either an INSERT or </span><span class="cx"> an UPDATE statement for each table used by this mapper, for each element of the </span><span class="cx"> list.""" </span><del>- </del><span class="cx"> #print "SAVE_OBJ MAPPER", self.class_.__name__, objects </span><span class="cx"> connection = uow.transaction.connection(self) </span><span class="cx"> for table in self.tables: </span><span class="lines">@@ -702,7 +701,6 @@ </span><span class="cx"> def delete_obj(self, objects, uow): </span><span class="cx"> """called by a UnitOfWork object to delete objects, which involves a </span><span class="cx"> DELETE statement for each table used by this mapper, for each object in the list.""" </span><del>- </del><span class="cx"> connection = uow.transaction.connection(self) </span><span class="cx"> </span><span class="cx"> for table in util.reversed(self.tables): </span><span class="lines">@@ -826,9 +824,6 @@ </span><span class="cx"> return instance </span><span class="cx"> </span><span class="cx"> def _create_instance(self, session): </span><del>- - #return self.class_(_mapper_nohistory=True, _sa_entity_name=self.entity_name, _sa_session=session) - </del><span class="cx"> obj = self.class_.__new__(self.class_) </span><span class="cx"> obj._entity_name = self.entity_name </span><span class="cx"> </span><span class="lines">@@ -836,8 +831,6 @@ </span><span class="cx"> # in order to save on KeyErrors later on </span><span class="cx"> sessionlib.global_attributes.init_attr(obj) </span><span class="cx"> </span><del>-# TODO: this _attach should not be needed.... -# session._attach(obj) </del><span class="cx"> return obj </span><span class="cx"> </span><span class="cx"> def translate_row(self, tomapper, row): </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemysqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/sql.py (1427 => 1428)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/sql.py 2006-05-08 18:43:43 UTC (rev 1427) +++ sqlalchemy/branches/schema/lib/sqlalchemy/sql.py 2006-05-08 19:00:51 UTC (rev 1428) </span><span class="lines">@@ -208,8 +208,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 - an optional engine to be used for this text query. Alternatively, call the - text() method off the engine directly. </del><ins>+ engine - an optional engine to be used for this text query. </ins><span class="cx"> </span><span class="cx"> bindparams - a list of bindparam() instances which can be used to define the </span><span class="cx"> types and/or initial values for the bind parameters within the textual statement; </span><span class="lines">@@ -246,13 +245,14 @@ </span><span class="cx"> return isinstance(col, ColumnElement) </span><span class="cx"> </span><span class="cx"> class Engine(object): </span><del>- """represents a 'thing that can produce Compiler objects and execute them'.""" </del><ins>+ """represents a 'thing that can produce Compiled objects and execute them'.""" </ins><span class="cx"> def execute_compiled(self, compiled, parameters, echo=None, **kwargs): </span><span class="cx"> raise NotImplementedError() </span><span class="cx"> def compiler(self, statement, parameters, **kwargs): </span><span class="cx"> raise NotImplementedError() </span><span class="cx"> </span><span class="cx"> class AbstractDialect(object): </span><ins>+ """represents the behavior of a particular database. Used by Compiled objects.""" </ins><span class="cx"> pass </span><span class="cx"> </span><span class="cx"> class ClauseParameters(util.OrderedDict): </span><span class="lines">@@ -457,7 +457,7 @@ </span><span class="cx"> def compile(self, engine=None, parameters=None, compiler=None, dialect=None): </span><span class="cx"> """compiles this SQL expression. </span><span class="cx"> </span><del>- Uses the given Compiler, or the given Dialect or Engine to create a Compiler. If no compiler </del><ins>+ Uses the given Compiler, or the given AbstractDialect or Engine to create a Compiler. If no compiler </ins><span class="cx"> arguments are given, tries to use the underlying Engine this ClauseElement is bound </span><span class="cx"> to to create a Compiler, if any. Finally, if there is no bound Engine, uses an ANSIDialect </span><span class="cx"> to create a default Compiler. </span><span class="lines">@@ -598,13 +598,13 @@ </span><span class="cx"> class ColumnElement(Selectable, CompareMixin): </span><span class="cx"> """represents a column element within the list of a Selectable's columns. </span><span class="cx"> A ColumnElement can either be directly associated with a TableClause, or </span><del>- a free-standing textual column with no table, or is a "proxied" column, indicating - it is placed on a Selectable such as an Alias or Select statement and corresponds - to a TableClause attached column. in the case of a CompositeSelect, a ColumnElement - may correspond to several TableClause-attached columns. """ </del><ins>+ a free-standing textual column with no table, or is a "proxy" column, indicating + it is placed on a Selectable such as an Alias or Select statement and ultimately corresponds + to a TableClause-attached column (or in the case of a CompositeSelect, a proxy ColumnElement + may correspond to several TableClause-attached columns).""" </ins><span class="cx"> </span><span class="cx"> primary_key = property(lambda self:getattr(self, '_primary_key', False), doc="primary key flag. indicates if this Column represents part or whole of a primary key.") </span><del>- foreign_key = property(lambda self:getattr(self, '_foreign_key', False), doc="foreign key accessor. points to a ForeignKey object which represents a Foreign Key placed on this column") </del><ins>+ foreign_key = property(lambda self:getattr(self, '_foreign_key', False), doc="foreign key accessor. points to a ForeignKey object which represents a Foreign Key placed on this column's ultimate ancestor.") </ins><span class="cx"> columns = property(lambda self:[self], doc="Columns accessor which just returns self, to provide compatibility with Selectable objects.") </span><span class="cx"> </span><span class="cx"> def _get_orig_set(self): </span><span class="lines">@@ -617,9 +617,10 @@ </span><span class="cx"> if len(s) == 0: </span><span class="cx"> s.add(self) </span><span class="cx"> self.__orig_set = s </span><del>- orig_set = property(_get_orig_set, _set_orig_set,doc="""a Set containing Table-bound, non-proxied ColumnElements for which this ColumnElement is a proxy. In all cases except for a column proxied from a Union (i.e. CompoundSelect), this set will be just one element.""") </del><ins>+ orig_set = property(_get_orig_set, _set_orig_set,doc="""a Set containing TableClause-bound, non-proxied ColumnElements for which this ColumnElement is a proxy. In all cases except for a column proxied from a Union (i.e. CompoundSelect), this set will be just one element.""") </ins><span class="cx"> </span><span class="cx"> def shares_lineage(self, othercolumn): </span><ins>+ """returns True if the given ColumnElement has a common ancestor to this ColumnElement.""" </ins><span class="cx"> for c in self.orig_set: </span><span class="cx"> if c in othercolumn.orig_set: </span><span class="cx"> return True </span><span class="lines">@@ -627,10 +628,8 @@ </span><span class="cx"> return False </span><span class="cx"> def _make_proxy(self, selectable, name=None): </span><span class="cx"> """creates a new ColumnElement representing this ColumnElement as it appears in the select list </span><del>- of an enclosing selectable. The default implementation returns a ColumnClause if a name is given, - else just returns self. This has various mechanics with sql.ColumnClause and sql.Label so that - ColumnClause objects as well as non-column objects like Function and BinaryClause can both appear in the - select list of an enclosing selectable.""" </del><ins>+ of a descending selectable. The default implementation returns a ColumnClause if a name is given, + else just returns self.""" </ins><span class="cx"> if name is not None: </span><span class="cx"> co = ColumnClause(name, selectable) </span><span class="cx"> co.orig_set = self.orig_set </span><span class="lines">@@ -965,7 +964,6 @@ </span><span class="cx"> def __init__(self, left, right, onclause=None, isouter = False): </span><span class="cx"> self.left = left </span><span class="cx"> self.right = right </span><del>- # TODO: if no onclause, do NATURAL JOIN </del><span class="cx"> if onclause is None: </span><span class="cx"> self.onclause = self._match_primaries(left, right) </span><span class="cx"> else: </span><span class="lines">@@ -1085,7 +1083,6 @@ </span><span class="cx"> self.type = sqltypes.to_instance(type) </span><span class="cx"> obj.parens=True </span><span class="cx"> key = property(lambda s: s.name) </span><del>- </del><span class="cx"> _label = property(lambda s: s.name) </span><span class="cx"> orig_set = property(lambda s:s.obj.orig_set) </span><span class="cx"> def accept_visitor(self, visitor): </span><span class="lines">@@ -1220,8 +1217,6 @@ </span><span class="cx"> </span><span class="cx"> class SelectBaseMixin(object): </span><span class="cx"> """base class for Select and CompoundSelects""" </span><del>- def __init__(self): - self.name = None </del><span class="cx"> def order_by(self, *clauses): </span><span class="cx"> if len(clauses) == 1 and clauses[0] is None: </span><span class="cx"> self.order_by_clause = ClauseList() </span><span class="lines">@@ -1259,14 +1254,15 @@ </span><span class="cx"> self.group_by(*kwargs.get('group_by', [None])) </span><span class="cx"> self.order_by(*kwargs.get('order_by', [None])) </span><span class="cx"> self._col_map = {} </span><ins>+ + name = property(lambda s:s.keyword + " statement") + </ins><span class="cx"> def _locate_oid_column(self): </span><span class="cx"> return self.selects[0].oid_column </span><del>- </del><span class="cx"> def _exportable_columns(self): </span><span class="cx"> for s in self.selects: </span><span class="cx"> for c in s.c: </span><span class="cx"> yield c </span><del>- </del><span class="cx"> def _proxy_column(self, column): </span><span class="cx"> if self.use_labels: </span><span class="cx"> col = column._make_proxy(self, name=column._label) </span><span class="lines">@@ -1348,7 +1344,8 @@ </span><span class="cx"> for f in from_obj: </span><span class="cx"> self.append_from(f) </span><span class="cx"> </span><del>- </del><ins>+ name = property(lambda s:"SELECT statement") + </ins><span class="cx"> class CorrelatedVisitor(ClauseVisitor): </span><span class="cx"> """visits a clause, locates any Select clauses, and tells them that they should </span><span class="cx"> correlate their FROM list to that of their parent.""" </span><span class="lines">@@ -1445,14 +1442,6 @@ </span><span class="cx"> return union(self, other, **kwargs) </span><span class="cx"> def union_all(self, other, **kwargs): </span><span class="cx"> return union_all(self, other, **kwargs) </span><del>- -# def scalar(self, *multiparams, **params): - # need to set limit=1, but only in this thread. - # we probably need to make a copy of the select(). this - # is expensive. I think cursor.fetchone(), then discard remaining results - # should be fine with most DBs - # for now use base scalar() method - </del><span class="cx"> def _find_engine(self): </span><span class="cx"> """tries to return a Engine, either explicitly set in this object, or searched </span><span class="cx"> within the from clauses for one""" </span><span class="lines">@@ -1470,7 +1459,6 @@ </span><span class="cx"> </span><span class="cx"> class UpdateBase(ClauseElement): </span><span class="cx"> """forms the base for INSERT, UPDATE, and DELETE statements.""" </span><del>- </del><span class="cx"> def _process_colparams(self, parameters): </span><span class="cx"> """receives the "values" of an INSERT or UPDATE statement and constructs </span><span class="cx"> appropriate ind parameters.""" </span><span class="lines">@@ -1499,10 +1487,8 @@ </span><span class="cx"> except KeyError: </span><span class="cx"> del parameters[key] </span><span class="cx"> return parameters </span><del>- </del><span class="cx"> def _find_engine(self): </span><span class="cx"> return self.table.engine </span><del>- </del><span class="cx"> </span><span class="cx"> class Insert(UpdateBase): </span><span class="cx"> def __init__(self, table, values=None, **params): </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-05-08 18:44:22
|
<!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>[1427] sqlalchemy/branches/schema/test: column.original removed totally ! _get_col_by_original changed to corresponding_column</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1427</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-05-08 13:43:43 -0500 (Mon, 08 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>column.original removed totally ! _get_col_by_original changed to corresponding_column</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemalibsqlalchemydatabasesmssqlpy">sqlalchemy/branches/schema/lib/sqlalchemy/databases/mssql.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemydatabasesoraclepy">sqlalchemy/branches/schema/lib/sqlalchemy/databases/oracle.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyormmapperpy">sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyormpropertiespy">sqlalchemy/branches/schema/lib/sqlalchemy/orm/properties.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyschemapy">sqlalchemy/branches/schema/lib/sqlalchemy/schema.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemysqlpy">sqlalchemy/branches/schema/lib/sqlalchemy/sql.py</a></li> <li><a href="#sqlalchemybranchesschematestobjectstorepy">sqlalchemy/branches/schema/test/objectstore.py</a></li> <li><a href="#sqlalchemybranchesschematestselectpy">sqlalchemy/branches/schema/test/select.py</a></li> <li><a href="#sqlalchemybranchesschematestselectablepy">sqlalchemy/branches/schema/test/selectable.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschemalibsqlalchemydatabasesmssqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/databases/mssql.py (1426 => 1427)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/databases/mssql.py 2006-05-08 18:28:08 UTC (rev 1426) +++ sqlalchemy/branches/schema/lib/sqlalchemy/databases/mssql.py 2006-05-08 18:43:43 UTC (rev 1427) </span><span class="lines">@@ -455,7 +455,7 @@ </span><span class="cx"> super(MSSQLCompiler, self).visit_column(column) </span><span class="cx"> if column.table is not None and self.tablealiases.has_key(column.table): </span><span class="cx"> self.strings[column] = \ </span><del>- self.strings[self.tablealiases[column.table]._get_col_by_original(column.original)] </del><ins>+ self.strings[self.tablealiases[column.table].corresponding_column(column.original)] </ins><span class="cx"> </span><span class="cx"> </span><span class="cx"> class MSSQLSchemaGenerator(ansisql.ANSISchemaGenerator): </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemydatabasesoraclepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/databases/oracle.py (1426 => 1427)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/databases/oracle.py 2006-05-08 18:28:08 UTC (rev 1426) +++ sqlalchemy/branches/schema/lib/sqlalchemy/databases/oracle.py 2006-05-08 18:43:43 UTC (rev 1427) </span><span class="lines">@@ -274,18 +274,13 @@ </span><span class="cx"> self.strings[select.order_by_clause] = "" </span><span class="cx"> ansisql.ANSICompiler.visit_select(self, select) </span><span class="cx"> return </span><ins>+ </ins><span class="cx"> if select.limit is not None or select.offset is not None: </span><span class="cx"> select._oracle_visit = True </span><ins>+ # to use ROW_NUMBER(), an ORDER BY is required. </ins><span class="cx"> orderby = self.strings[select.order_by_clause] </span><span class="cx"> if not orderby: </span><del>- # to use ROW_NUMBER(), an ORDER BY is required. so here we dig in - # as best we can to find some column we can order by - # TODO: try to get "oid_column" to be used here - if len(select.primary_key): - col = select.primary_key[0].original.table.name - else: - col = [c for c in select.c][0].original.table.name - orderby = "%s.rowid ASC" % col </del><ins>+ orderby = select.oid_column </ins><span class="cx"> select.append_column(sql.ColumnClause("ROW_NUMBER() OVER (ORDER BY %s)" % orderby).label("ora_rn")) </span><span class="cx"> limitselect = sql.select([c for c in select.c if c.key!='ora_rn']) </span><span class="cx"> if select.offset is not None: </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyormmapperpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py (1426 => 1427)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py 2006-05-08 18:28:08 UTC (rev 1426) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py 2006-05-08 18:43:43 UTC (rev 1427) </span><span class="lines">@@ -341,14 +341,14 @@ </span><span class="cx"> </span><span class="cx"> if sql.is_column(prop): </span><span class="cx"> try: </span><del>- prop = self.select_table._get_col_by_original(prop) </del><ins>+ prop = self.select_table.corresponding_column(prop) </ins><span class="cx"> except KeyError: </span><span class="cx"> raise exceptions.ArgumentError("Column '%s' is not represented in mapper's table" % prop._label) </span><span class="cx"> self.columns[key] = prop </span><span class="cx"> prop = ColumnProperty(prop) </span><span class="cx"> elif isinstance(prop, list) and sql.is_column(prop[0]): </span><span class="cx"> try: </span><del>- prop = [self.select_table._get_col_by_original(p) for p in prop] </del><ins>+ prop = [self.select_table.corresponding_column(p) for p in prop] </ins><span class="cx"> except KeyError, e: </span><span class="cx"> raise exceptions.ArgumentError("Column '%s' is not represented in mapper's table" % e.args[0]) </span><span class="cx"> self.columns[key] = prop[0] </span><span class="lines">@@ -847,7 +847,7 @@ </span><span class="cx"> examples.""" </span><span class="cx"> newrow = util.DictDecorator(row) </span><span class="cx"> for c in tomapper.select_table.c: </span><del>- c2 = self.select_table._get_col_by_original(c) </del><ins>+ c2 = self.select_table.corresponding_column(c) </ins><span class="cx"> newrow[c] = row[c2] </span><span class="cx"> return newrow </span><span class="cx"> </span><span class="lines">@@ -1034,19 +1034,19 @@ </span><span class="cx"> super(TranslatingDict, self).__init__() </span><span class="cx"> self.selectable = selectable </span><span class="cx"> def __getitem__(self, col): </span><del>- ourcol = self.selectable._get_col_by_original(col) </del><ins>+ ourcol = self.selectable.corresponding_column(col) </ins><span class="cx"> return super(TranslatingDict, self).__getitem__(ourcol) </span><span class="cx"> def has_key(self, col): </span><del>- ourcol = self.selectable._get_col_by_original(col) </del><ins>+ ourcol = self.selectable.corresponding_column(col) </ins><span class="cx"> return super(TranslatingDict, self).has_key(ourcol) </span><span class="cx"> def __setitem__(self, col, value): </span><del>- ourcol = self.selectable._get_col_by_original(col) </del><ins>+ ourcol = self.selectable.corresponding_column(col) </ins><span class="cx"> return super(TranslatingDict, self).__setitem__(ourcol, value) </span><span class="cx"> def __contains__(self, col): </span><del>- ourcol = self.selectable._get_col_by_original(col) </del><ins>+ ourcol = self.selectable.corresponding_column(col) </ins><span class="cx"> return super(TranslatingDict, self).__contains__(ourcol) </span><span class="cx"> def setdefault(self, col, value): </span><del>- ourcol = self.selectable._get_col_by_original(col) </del><ins>+ ourcol = self.selectable.corresponding_column(col) </ins><span class="cx"> return super(TranslatingDict, self).setdefault(ourcol, value) </span><span class="cx"> </span><span class="cx"> class ClassKey(object): </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyormpropertiespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/properties.py (1426 => 1427)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/properties.py 2006-05-08 18:28:08 UTC (rev 1426) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/properties.py 2006-05-08 18:43:43 UTC (rev 1427) </span><span class="lines">@@ -34,7 +34,7 @@ </span><span class="cx"> def setup(self, key, statement, eagertable=None, **options): </span><span class="cx"> for c in self.columns: </span><span class="cx"> if eagertable is not None: </span><del>- statement.append_column(eagertable._get_col_by_original(c)) </del><ins>+ statement.append_column(eagertable.corresponding_column(c)) </ins><span class="cx"> else: </span><span class="cx"> statement.append_column(c) </span><span class="cx"> def do_init(self, key, parent): </span><span class="lines">@@ -528,7 +528,7 @@ </span><span class="cx"> orderby = util.to_list(orderby) </span><span class="cx"> for i in range(0, len(orderby)): </span><span class="cx"> if isinstance(orderby[i], schema.Column): </span><del>- orderby[i] = self.eagertarget._get_col_by_original(orderby[i]) </del><ins>+ orderby[i] = self.eagertarget.corresponding_column(orderby[i]) </ins><span class="cx"> else: </span><span class="cx"> orderby[i].accept_visitor(self.aliasizer) </span><span class="cx"> return orderby </span><span class="lines">@@ -609,7 +609,7 @@ </span><span class="cx"> return map.keys() </span><span class="cx"> map = {} </span><span class="cx"> for c in self.eagertarget.c: </span><del>- parent = self.target._get_col_by_original(c) </del><ins>+ parent = self.target.corresponding_column(c) </ins><span class="cx"> map[parent] = c </span><span class="cx"> map[parent._label] = c </span><span class="cx"> map[parent.name] = c </span><span class="lines">@@ -758,14 +758,14 @@ </span><span class="cx"> for i in range(0, len(clist.clauses)): </span><span class="cx"> if isinstance(clist.clauses[i], schema.Column) and self.tables.has_key(clist.clauses[i].table): </span><span class="cx"> orig = clist.clauses[i] </span><del>- clist.clauses[i] = self.get_alias(clist.clauses[i].table)._get_col_by_original(clist.clauses[i]) </del><ins>+ clist.clauses[i] = self.get_alias(clist.clauses[i].table).corresponding_column(clist.clauses[i]) </ins><span class="cx"> if clist.clauses[i] is None: </span><span class="cx"> raise "cant get orig for " + str(orig) + " against table " + orig.table.name + " " + self.get_alias(orig.table).name </span><span class="cx"> def visit_binary(self, binary): </span><span class="cx"> if isinstance(binary.left, schema.Column) and self.tables.has_key(binary.left.table): </span><del>- binary.left = self.get_alias(binary.left.table)._get_col_by_original(binary.left) </del><ins>+ binary.left = self.get_alias(binary.left.table).corresponding_column(binary.left) </ins><span class="cx"> if isinstance(binary.right, schema.Column) and self.tables.has_key(binary.right.table): </span><del>- binary.right = self.get_alias(binary.right.table)._get_col_by_original(binary.right) </del><ins>+ binary.right = self.get_alias(binary.right.table).corresponding_column(binary.right) </ins><span class="cx"> </span><span class="cx"> class BinaryVisitor(sql.ClauseVisitor): </span><span class="cx"> def __init__(self, func): </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyschemapy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/schema.py (1426 => 1427)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/schema.py 2006-05-08 18:28:08 UTC (rev 1426) +++ sqlalchemy/branches/schema/lib/sqlalchemy/schema.py 2006-05-08 18:43:43 UTC (rev 1427) </span><span class="lines">@@ -414,7 +414,7 @@ </span><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><del>- return table._get_col_by_original(self.column, False) is not None </del><ins>+ return table.corresponding_column(self.column, False) is not None </ins><span class="cx"> </span><span class="cx"> def _init_column(self): </span><span class="cx"> # ForeignKey inits its remote column as late as possible, so tables can </span><span class="lines">@@ -426,10 +426,10 @@ </span><span class="cx"> raise ArgumentError("Invalid foreign key column specification: " + self._colspec) </span><span class="cx"> if m.group(3) is None: </span><span class="cx"> (tname, colname) = m.group(1, 2) </span><del>- schema = self.parent.original.table.schema </del><ins>+ schema = list(self.parent.orig_set)[0].table.schema </ins><span class="cx"> else: </span><span class="cx"> (schema,tname,colname) = m.group(1,2,3) </span><del>- table = Table(tname, self.parent.original.metadata, mustexist=True, schema=schema) </del><ins>+ table = Table(tname, list(self.parent.orig_set)[0].metadata, mustexist=True, schema=schema) </ins><span class="cx"> if colname is None: </span><span class="cx"> key = self.parent </span><span class="cx"> self._column = table.c[self.parent.key] </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemysqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/sql.py (1426 => 1427)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/sql.py 2006-05-08 18:28:08 UTC (rev 1426) +++ sqlalchemy/branches/schema/lib/sqlalchemy/sql.py 2006-05-08 18:43:43 UTC (rev 1427) </span><span class="lines">@@ -617,15 +617,8 @@ </span><span class="cx"> if len(s) == 0: </span><span class="cx"> s.add(self) </span><span class="cx"> self.__orig_set = s </span><del>- self.__original = list(s)[0] - def _get_original(self): - try: - return self.__original - except AttributeError: - self.__original = list(self.orig_set)[0] - return self.__original </del><span class="cx"> orig_set = property(_get_orig_set, _set_orig_set,doc="""a Set containing Table-bound, non-proxied ColumnElements for which this ColumnElement is a proxy. In all cases except for a column proxied from a Union (i.e. CompoundSelect), this set will be just one element.""") </span><del>- original = property(_get_original, doc="Scalar version of orig_set, which is usually one element. If orig_set contains multiple columns, this will represent just one of the columns.") </del><ins>+ </ins><span class="cx"> def shares_lineage(self, othercolumn): </span><span class="cx"> for c in self.orig_set: </span><span class="cx"> if c in othercolumn.orig_set: </span><span class="lines">@@ -672,7 +665,7 @@ </span><span class="cx"> if not hasattr(self, '_oid_column'): </span><span class="cx"> self._oid_column = self._locate_oid_column() </span><span class="cx"> return self._oid_column </span><del>- def _get_col_by_original(self, column, raiseerr=True): </del><ins>+ def corresponding_column(self, column, raiseerr=True): </ins><span class="cx"> """given a ColumnElement, return the ColumnElement object from this </span><span class="cx"> Selectable which corresponds to that original Column via a proxy relationship.""" </span><span class="cx"> for c in column.orig_set: </span><span class="lines">@@ -717,7 +710,8 @@ </span><span class="cx"> for ci in cp.orig_set: </span><span class="cx"> self._orig_cols[ci] = cp </span><span class="cx"> if self.oid_column is not None: </span><del>- self._orig_cols[self.oid_column.original] = self.oid_column </del><ins>+ for ci in self.oid_column.orig_set: + self._orig_cols[ci] = self.oid_column </ins><span class="cx"> def _exportable_columns(self): </span><span class="cx"> return [] </span><span class="cx"> def _proxy_column(self, column): </span><span class="lines">@@ -995,12 +989,12 @@ </span><span class="cx"> crit = [] </span><span class="cx"> for fk in secondary.foreign_keys: </span><span class="cx"> if fk.references(primary): </span><del>- crit.append(primary._get_col_by_original(fk.column) == fk.parent) </del><ins>+ crit.append(primary.corresponding_column(fk.column) == fk.parent) </ins><span class="cx"> self.foreignkey = fk.parent </span><span class="cx"> if primary is not secondary: </span><span class="cx"> for fk in primary.foreign_keys: </span><span class="cx"> if fk.references(secondary): </span><del>- crit.append(secondary._get_col_by_original(fk.column) == fk.parent) </del><ins>+ crit.append(secondary.corresponding_column(fk.column) == fk.parent) </ins><span class="cx"> self.foreignkey = fk.parent </span><span class="cx"> if len(crit) == 0: </span><span class="cx"> raise exceptions.ArgumentError("Cant find any foreign key relationships between '%s' and '%s'" % (primary.name, secondary.name)) </span><span class="lines">@@ -1128,7 +1122,7 @@ </span><span class="cx"> </span><span class="cx"> for example, this could translate the column "name" from a Table object </span><span class="cx"> to an Alias of a Select off of that Table object.""" </span><del>- return selectable._get_col_by_original(self.original, False) </del><ins>+ return selectable.corresponding_column(self.original, False) </ins><span class="cx"> def _get_from_objects(self): </span><span class="cx"> if self.table is not None: </span><span class="cx"> return [self.table] </span><span class="lines">@@ -1175,7 +1169,8 @@ </span><span class="cx"> except AttributeError: </span><span class="cx"> self._orig_cols= {} </span><span class="cx"> for c in self.columns: </span><del>- self._orig_cols[c.original] = c </del><ins>+ for ci in c.orig_set: + self._orig_cols[ci] = c </ins><span class="cx"> return self._orig_cols </span><span class="cx"> columns = property(lambda s:s._columns) </span><span class="cx"> c = property(lambda s:s._columns) </span></span></pre></div> <a id="sqlalchemybranchesschematestobjectstorepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/test/objectstore.py (1426 => 1427)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/test/objectstore.py 2006-05-08 18:28:08 UTC (rev 1426) +++ sqlalchemy/branches/schema/test/objectstore.py 2006-05-08 18:43:43 UTC (rev 1427) </span><span class="lines">@@ -512,7 +512,7 @@ </span><span class="cx"> """tests a save of an object where each instance spans two tables. also tests </span><span class="cx"> redefinition of the keynames for the column properties.""" </span><span class="cx"> usersaddresses = sql.join(users, addresses, users.c.user_id == addresses.c.user_id) </span><del>- print usersaddresses._get_col_by_original(users.c.user_id) </del><ins>+ print usersaddresses.corresponding_column(users.c.user_id) </ins><span class="cx"> print repr(usersaddresses._orig_cols) </span><span class="cx"> m = mapper(User, usersaddresses, </span><span class="cx"> properties = dict( </span></span></pre></div> <a id="sqlalchemybranchesschematestselectpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/test/select.py (1426 => 1427)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/test/select.py 2006-05-08 18:28:08 UTC (rev 1426) +++ sqlalchemy/branches/schema/test/select.py 2006-05-08 18:43:43 UTC (rev 1427) </span><span class="lines">@@ -465,7 +465,7 @@ </span><span class="cx"> select([table2]), </span><span class="cx"> select([table3]) </span><span class="cx"> ) </span><del>- assert u._get_col_by_original(table2.c.otherid) is u.c.otherid </del><ins>+ assert u.corresponding_column(table2.c.otherid) is u.c.otherid </ins><span class="cx"> </span><span class="cx"> </span><span class="cx"> def testouterjoin(self): </span></span></pre></div> <a id="sqlalchemybranchesschematestselectablepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/test/selectable.py (1426 => 1427)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/test/selectable.py 2006-05-08 18:28:08 UTC (rev 1426) +++ sqlalchemy/branches/schema/test/selectable.py 2006-05-08 18:43:43 UTC (rev 1427) </span><span class="lines">@@ -47,10 +47,10 @@ </span><span class="cx"> s1 = table.select(use_labels=True) </span><span class="cx"> s2 = table2.select(use_labels=True) </span><span class="cx"> print ["%d %s" % (id(c),c.key) for c in u.c] </span><del>- c = u._get_col_by_original(s1.c.table1_col2) </del><ins>+ c = u.corresponding_column(s1.c.table1_col2) </ins><span class="cx"> print "%d %s" % (id(c), c.key) </span><del>- assert u._get_col_by_original(s1.c.table1_col2) is u.c.col2 - assert u._get_col_by_original(s2.c.table2_col2) is u.c.col2 </del><ins>+ assert u.corresponding_column(s1.c.table1_col2) is u.c.col2 + assert u.corresponding_column(s2.c.table2_col2) is u.c.col2 </ins><span class="cx"> </span><span class="cx"> def testaliasunion(self): </span><span class="cx"> # same as testunion, except its an alias of the union </span><span class="lines">@@ -60,10 +60,10 @@ </span><span class="cx"> s1 = table.select(use_labels=True) </span><span class="cx"> s2 = table2.select(use_labels=True) </span><span class="cx"> print ["%d %s" % (id(c),c.key) for c in u.c] </span><del>-# c = u._get_col_by_original(s1.c.table1_col2) </del><ins>+# c = u.corresponding_column(s1.c.table1_col2) </ins><span class="cx"> print "%d %s" % (id(c), c.key) </span><del>- assert u._get_col_by_original(s1.c.table1_col2) is u.c.col2 - assert u._get_col_by_original(s2.c.table2_col2) is u.c.col2 </del><ins>+ assert u.corresponding_column(s1.c.table1_col2) is u.c.col2 + assert u.corresponding_column(s2.c.table2_col2) is u.c.col2 </ins><span class="cx"> </span><span class="cx"> def testselectunion(self): </span><span class="cx"> # like testaliasunion, but off a Select off the union. </span><span class="lines">@@ -73,8 +73,8 @@ </span><span class="cx"> s = select([u]) </span><span class="cx"> s1 = table.select(use_labels=True) </span><span class="cx"> s2 = table2.select(use_labels=True) </span><del>- assert s._get_col_by_original(s1.c.table1_col2) is s.c.col2 - assert s._get_col_by_original(s2.c.table2_col2) is s.c.col2 </del><ins>+ assert s.corresponding_column(s1.c.table1_col2) is s.c.col2 + assert s.corresponding_column(s2.c.table2_col2) is s.c.col2 </ins><span class="cx"> </span><span class="cx"> def testunionagainstjoin(self): </span><span class="cx"> # same as testunion, except its an alias of the union </span><span class="lines">@@ -82,8 +82,8 @@ </span><span class="cx"> select([table2.c.col1, table2.c.col2, table2.c.col3, null().label('colx'), table2.c.coly]) </span><span class="cx"> ).alias('analias') </span><span class="cx"> j1 = table.join(table2) </span><del>- assert u._get_col_by_original(j1.c.table1_colx) is u.c.colx - assert j1._get_col_by_original(u.c.colx) is j1.c.table1_colx </del><ins>+ assert u.corresponding_column(j1.c.table1_colx) is u.c.colx + assert j1.corresponding_column(u.c.colx) is j1.c.table1_colx </ins><span class="cx"> </span><span class="cx"> def testjoin(self): </span><span class="cx"> a = join(table, table2) </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-05-08 18:28:29
|
<!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>[1426] sqlalchemy/branches/schema/lib/sqlalchemy: completely removed usage of "column.original" from Mapper, uses _get_col_by_original totally.</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1426</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-05-08 13:28:08 -0500 (Mon, 08 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>completely removed usage of "column.original" from Mapper, uses _get_col_by_original totally.</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemalibsqlalchemyenginebasepy">sqlalchemy/branches/schema/lib/sqlalchemy/engine/base.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyormmapperpy">sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemysqlpy">sqlalchemy/branches/schema/lib/sqlalchemy/sql.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschemalibsqlalchemyenginebasepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/engine/base.py (1425 => 1426)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/engine/base.py 2006-05-08 17:40:17 UTC (rev 1425) +++ sqlalchemy/branches/schema/lib/sqlalchemy/engine/base.py 2006-05-08 18:28:08 UTC (rev 1426) </span><span class="lines">@@ -496,7 +496,7 @@ </span><span class="cx"> if self.connection.close_with_result and self.dialect.supports_autoclose_results: </span><span class="cx"> self.connection.close() </span><span class="cx"> def _get_col(self, row, key): </span><del>- if isinstance(key, schema.Column) or isinstance(key, sql.ColumnElement): </del><ins>+ if isinstance(key, sql.ColumnElement): </ins><span class="cx"> try: </span><span class="cx"> rec = self.props[key._label.lower()] </span><span class="cx"> #print "GOT IT FROM LABEL FOR ", key._label </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyormmapperpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py (1425 => 1426)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py 2006-05-08 17:40:17 UTC (rev 1425) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py 2006-05-08 18:28:08 UTC (rev 1426) </span><span class="lines">@@ -191,7 +191,7 @@ </span><span class="cx"> # table columns mapped to lists of MapperProperty objects </span><span class="cx"> # using a list allows a single column to be defined as </span><span class="cx"> # populating multiple object attributes </span><del>- self.columntoproperty = {} </del><ins>+ self.columntoproperty = TranslatingDict(self.select_table) </ins><span class="cx"> </span><span class="cx"> # load custom properties </span><span class="cx"> if properties is not None: </span><span class="lines">@@ -204,7 +204,7 @@ </span><span class="cx"> if not self.columns.has_key(column.key): </span><span class="cx"> self.columns[column.key] = column </span><span class="cx"> </span><del>- if self.columntoproperty.has_key(column.original): </del><ins>+ if self.columntoproperty.has_key(column): </ins><span class="cx"> continue </span><span class="cx"> </span><span class="cx"> prop = self.props.get(column.key, None) </span><span class="lines">@@ -227,9 +227,8 @@ </span><span class="cx"> </span><span class="cx"> # its a ColumnProperty - match the ultimate table columns </span><span class="cx"> # back to the property </span><del>- for c in column.orig_set: - proplist = self.columntoproperty.setdefault(c.original, []) - proplist.append(prop) </del><ins>+ proplist = self.columntoproperty.setdefault(column, []) + proplist.append(prop) </ins><span class="cx"> </span><span class="cx"> if not non_primary and (not mapper_registry.has_key(self.class_key) or self.is_primary or (inherits is not None and inherits._is_primary_mapper())): </span><span class="cx"> sessionlib.global_attributes.reset_class_managed(self.class_) </span><span class="lines">@@ -253,12 +252,6 @@ </span><span class="cx"> if getattr(prop, 'key', None) is None: </span><span class="cx"> prop.init(key, self) </span><span class="cx"> </span><del>- # this prints a summary of the object attributes and how they - # will be mapped to table columns - #print "mapper %s, columntoproperty:" % (self.class_.__name__) - #for key, value in self.columntoproperty.iteritems(): - # print key.table.name, key.key, [(v.key, v) for v in value] - </del><span class="cx"> def add_polymorphic_mapping(self, key, class_or_mapper, entity_name=None): </span><span class="cx"> if isinstance(class_or_mapper, type): </span><span class="cx"> class_or_mapper = class_mapper(class_or_mapper, entity_name=entity_name) </span><span class="lines">@@ -363,9 +356,8 @@ </span><span class="cx"> self.props[key] = prop </span><span class="cx"> if isinstance(prop, ColumnProperty): </span><span class="cx"> for col in prop.columns: </span><del>- for c in col.orig_set: - proplist = self.columntoproperty.setdefault(c.original, []) - proplist.append(prop) </del><ins>+ proplist = self.columntoproperty.setdefault(col, []) + proplist.append(prop) </ins><span class="cx"> </span><span class="cx"> if init: </span><span class="cx"> prop.init(key, self) </span><span class="lines">@@ -520,7 +512,7 @@ </span><span class="cx"> </span><span class="cx"> def _getpropbycolumn(self, column, raiseerror=True): </span><span class="cx"> try: </span><del>- prop = self.columntoproperty[column.original] </del><ins>+ prop = self.columntoproperty[column] </ins><span class="cx"> except KeyError: </span><span class="cx"> try: </span><span class="cx"> prop = self.props[column.key] </span><span class="lines">@@ -540,7 +532,7 @@ </span><span class="cx"> return prop.getattr(obj) </span><span class="cx"> </span><span class="cx"> def _setattrbycolumn(self, obj, column, value): </span><del>- self.columntoproperty[column.original][0].setattr(obj, value) </del><ins>+ self.columntoproperty[column][0].setattr(obj, value) </ins><span class="cx"> </span><span class="cx"> def primary_mapper(self): </span><span class="cx"> return mapper_registry[self.class_key] </span><span class="lines">@@ -610,7 +602,7 @@ </span><span class="cx"> value = self._getattrbycolumn(obj, col) </span><span class="cx"> if value is not None: </span><span class="cx"> params[col.key] = value </span><del>- elif self.effective_polymorphic_on is not None and col.original is self.effective_polymorphic_on.original: </del><ins>+ elif self.effective_polymorphic_on is not None and self.effective_polymorphic_on.shares_lineage(col): </ins><span class="cx"> if isinsert: </span><span class="cx"> value = self.polymorphic_identity </span><span class="cx"> if col.default is None or value is not None: </span><span class="lines">@@ -742,7 +734,7 @@ </span><span class="cx"> def _has_pks(self, table): </span><span class="cx"> try: </span><span class="cx"> for k in self.pks_by_table[table]: </span><del>- if not self.columntoproperty.has_key(k.original): </del><ins>+ if not self.columntoproperty.has_key(k): </ins><span class="cx"> return False </span><span class="cx"> else: </span><span class="cx"> return True </span><span class="lines">@@ -1033,6 +1025,30 @@ </span><span class="cx"> if self.next is not None: </span><span class="cx"> self.next.before_delete(mapper, connection, instance) </span><span class="cx"> </span><ins>+class TranslatingDict(dict): + """a dictionary that stores ColumnElement objects as keys. incoming ColumnElement + keys are translated against those of an underling FromClause for all operations. + This way the columns from any Selectable that is derived from or underlying this + TranslatingDict's selectable can be used as keys.""" + def __init__(self, selectable): + super(TranslatingDict, self).__init__() + self.selectable = selectable + def __getitem__(self, col): + ourcol = self.selectable._get_col_by_original(col) + return super(TranslatingDict, self).__getitem__(ourcol) + def has_key(self, col): + ourcol = self.selectable._get_col_by_original(col) + return super(TranslatingDict, self).has_key(ourcol) + def __setitem__(self, col, value): + ourcol = self.selectable._get_col_by_original(col) + return super(TranslatingDict, self).__setitem__(ourcol, value) + def __contains__(self, col): + ourcol = self.selectable._get_col_by_original(col) + return super(TranslatingDict, self).__contains__(ourcol) + def setdefault(self, col, value): + ourcol = self.selectable._get_col_by_original(col) + return super(TranslatingDict, self).setdefault(ourcol, value) + </ins><span class="cx"> class ClassKey(object): </span><span class="cx"> """keys a class and an entity name to a mapper, via the mapper_registry""" </span><span class="cx"> def __init__(self, class_, entity_name): </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemysqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/sql.py (1425 => 1426)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/sql.py 2006-05-08 17:40:17 UTC (rev 1425) +++ sqlalchemy/branches/schema/lib/sqlalchemy/sql.py 2006-05-08 18:28:08 UTC (rev 1426) </span><span class="lines">@@ -626,7 +626,12 @@ </span><span class="cx"> return self.__original </span><span class="cx"> orig_set = property(_get_orig_set, _set_orig_set,doc="""a Set containing Table-bound, non-proxied ColumnElements for which this ColumnElement is a proxy. In all cases except for a column proxied from a Union (i.e. CompoundSelect), this set will be just one element.""") </span><span class="cx"> original = property(_get_original, doc="Scalar version of orig_set, which is usually one element. If orig_set contains multiple columns, this will represent just one of the columns.") </span><del>- </del><ins>+ def shares_lineage(self, othercolumn): + for c in self.orig_set: + if c in othercolumn.orig_set: + return True + else: + return False </ins><span class="cx"> def _make_proxy(self, selectable, name=None): </span><span class="cx"> """creates a new ColumnElement representing this ColumnElement as it appears in the select list </span><span class="cx"> of an enclosing selectable. The default implementation returns a ColumnClause if a name is given, </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-05-08 17:40:33
|
<!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>[1425] sqlalchemy/branches/schema/lib/sqlalchemy: "column.original" factored down to come from the same Set as column.orig_set</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1425</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-05-08 12:40:17 -0500 (Mon, 08 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>"column.original" factored down to come from the same Set as column.orig_set</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemalibsqlalchemyschemapy">sqlalchemy/branches/schema/lib/sqlalchemy/schema.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemysqlpy">sqlalchemy/branches/schema/lib/sqlalchemy/sql.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschemalibsqlalchemyschemapy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/schema.py (1424 => 1425)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/schema.py 2006-05-08 17:12:43 UTC (rev 1424) +++ sqlalchemy/branches/schema/lib/sqlalchemy/schema.py 2006-05-08 17:40:17 UTC (rev 1425) </span><span class="lines">@@ -300,13 +300,11 @@ </span><span class="cx"> if self.index is not None and self.unique is not None: </span><span class="cx"> raise ArgumentError("Column may not define both index and unique") </span><span class="cx"> self._foreign_key = None </span><del>- self._original = None </del><span class="cx"> if len(kwargs): </span><span class="cx"> raise ArgumentError("Unknown arguments passed to Column: " + repr(kwargs.keys())) </span><span class="cx"> </span><span class="cx"> primary_key = util.SimpleProperty('_primary_key') </span><span class="cx"> foreign_key = util.SimpleProperty('_foreign_key') </span><del>- original = property(lambda s: s._original or s) </del><span class="cx"> columns = property(lambda self:[self]) </span><span class="cx"> </span><span class="cx"> def _derived_metadata(self): </span><span class="lines">@@ -364,8 +362,7 @@ </span><span class="cx"> fk = self.foreign_key.copy() </span><span class="cx"> c = Column(name or self.name, self.type, fk, self.default, key = name or self.key, primary_key = self.primary_key, nullable = self.nullable, hidden = self.hidden) </span><span class="cx"> c.table = selectable </span><del>- c._original = self.original - c._orig_set = self.orig_set </del><ins>+ c.orig_set = self.orig_set </ins><span class="cx"> c._parent = self </span><span class="cx"> if not c.hidden: </span><span class="cx"> selectable.columns[c.key] = c </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemysqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/sql.py (1424 => 1425)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/sql.py 2006-05-08 17:12:43 UTC (rev 1424) +++ sqlalchemy/branches/schema/lib/sqlalchemy/sql.py 2006-05-08 17:40:17 UTC (rev 1425) </span><span class="lines">@@ -265,6 +265,7 @@ </span><span class="cx"> self[key] = value </span><span class="cx"> self.binds[key] = bindparam </span><span class="cx"> def get_original(self, key): </span><ins>+ """returns the given parameter as it was originally placed in this ClauseParameters object, without any Type conversion""" </ins><span class="cx"> return super(ClauseParameters, self).__getitem__(key) </span><span class="cx"> def __getitem__(self, key): </span><span class="cx"> v = super(ClauseParameters, self).__getitem__(key) </span><span class="lines">@@ -595,25 +596,36 @@ </span><span class="cx"> return True </span><span class="cx"> </span><span class="cx"> class ColumnElement(Selectable, CompareMixin): </span><del>- """represents a column element within the list of a Selectable's columns. Provides - default implementations for the things a "column" needs, including a "primary_key" flag, - a "foreign_key" accessor, an "original" accessor which represents the ultimate column - underlying a string of labeled/select-wrapped columns, and "columns" which returns a list - of the single column, providing the same list-based interface as a FromClause.""" - primary_key = property(lambda self:getattr(self, '_primary_key', False)) - foreign_key = property(lambda self:getattr(self, '_foreign_key', False)) </del><ins>+ """represents a column element within the list of a Selectable's columns. + A ColumnElement can either be directly associated with a TableClause, or + a free-standing textual column with no table, or is a "proxied" column, indicating + it is placed on a Selectable such as an Alias or Select statement and corresponds + to a TableClause attached column. in the case of a CompositeSelect, a ColumnElement + may correspond to several TableClause-attached columns. """ </ins><span class="cx"> </span><del>- columns = property(lambda self:[self]) </del><ins>+ primary_key = property(lambda self:getattr(self, '_primary_key', False), doc="primary key flag. indicates if this Column represents part or whole of a primary key.") + foreign_key = property(lambda self:getattr(self, '_foreign_key', False), doc="foreign key accessor. points to a ForeignKey object which represents a Foreign Key placed on this column") + columns = property(lambda self:[self], doc="Columns accessor which just returns self, to provide compatibility with Selectable objects.") </ins><span class="cx"> </span><del>- def _default_orig_set(self): </del><ins>+ def _get_orig_set(self): </ins><span class="cx"> try: </span><del>- return self._orig_set </del><ins>+ return self.__orig_set </ins><span class="cx"> except AttributeError: </span><del>- self._orig_set = sets.Set([self.original]) - return self._orig_set - # TODO: merge orig_set and original into just one Set - orig_set = property(_default_orig_set, doc="""a Set containing Table-bound, non-proxied ColumnElements for which this ColumnElement is a proxy. In all cases except for a column proxied from a Union (i.e. CompoundSelect), this set will be just one element.""") - original = property(lambda self:getattr(self, '_original', self), doc="Scalar version of orig_set, which is usually one element. For a column proxied through a CompoundSelect, this will be just one of the columns in orig_set.") </del><ins>+ self.__orig_set = sets.Set([self]) + return self.__orig_set + def _set_orig_set(self, s): + if len(s) == 0: + s.add(self) + self.__orig_set = s + self.__original = list(s)[0] + def _get_original(self): + try: + return self.__original + except AttributeError: + self.__original = list(self.orig_set)[0] + return self.__original + orig_set = property(_get_orig_set, _set_orig_set,doc="""a Set containing Table-bound, non-proxied ColumnElements for which this ColumnElement is a proxy. In all cases except for a column proxied from a Union (i.e. CompoundSelect), this set will be just one element.""") + original = property(_get_original, doc="Scalar version of orig_set, which is usually one element. If orig_set contains multiple columns, this will represent just one of the columns.") </ins><span class="cx"> </span><span class="cx"> def _make_proxy(self, selectable, name=None): </span><span class="cx"> """creates a new ColumnElement representing this ColumnElement as it appears in the select list </span><span class="lines">@@ -623,8 +635,7 @@ </span><span class="cx"> select list of an enclosing selectable.""" </span><span class="cx"> if name is not None: </span><span class="cx"> co = ColumnClause(name, selectable) </span><del>- co._original = self - co._orig_set = self.orig_set </del><ins>+ co.orig_set = self.orig_set </ins><span class="cx"> selectable.columns[name]= co </span><span class="cx"> return co </span><span class="cx"> else: </span><span class="lines">@@ -1077,7 +1088,7 @@ </span><span class="cx"> key = property(lambda s: s.name) </span><span class="cx"> </span><span class="cx"> _label = property(lambda s: s.name) </span><del>- original = property(lambda s:s.obj.original) </del><ins>+ orig_set = property(lambda s:s.obj.orig_set) </ins><span class="cx"> def accept_visitor(self, visitor): </span><span class="cx"> self.obj.accept_visitor(visitor) </span><span class="cx"> visitor.visit_label(self) </span><span class="lines">@@ -1125,8 +1136,7 @@ </span><span class="cx"> return BindParamClause(self._label, obj, shortname = self.name, type=self.type) </span><span class="cx"> def _make_proxy(self, selectable, name = None): </span><span class="cx"> c = ColumnClause(name or self.name, selectable, hidden=self.hidden) </span><del>- c._original = self.original - c._orig_set = self.orig_set </del><ins>+ c.orig_set = self.orig_set </ins><span class="cx"> if not self.hidden: </span><span class="cx"> selectable.columns[c.name] = c </span><span class="cx"> return c </span><span class="lines">@@ -1269,7 +1279,7 @@ </span><span class="cx"> colset = sets.Set() </span><span class="cx"> self._col_map[col.name] = colset </span><span class="cx"> [colset.add(c) for c in col.orig_set] </span><del>- col._orig_set = colset </del><ins>+ col.orig_set = colset </ins><span class="cx"> return col </span><span class="cx"> </span><span class="cx"> def accept_visitor(self, visitor): </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-05-08 17:12:59
|
<!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>[1424] sqlalchemy/branches/schema/lib/sqlalchemy: removed column "parent"</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1424</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-05-08 12:12:43 -0500 (Mon, 08 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>removed column "parent"</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemalibsqlalchemyschemapy">sqlalchemy/branches/schema/lib/sqlalchemy/schema.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemysqlpy">sqlalchemy/branches/schema/lib/sqlalchemy/sql.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschemalibsqlalchemyschemapy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/schema.py (1423 => 1424)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/schema.py 2006-05-08 17:10:07 UTC (rev 1423) +++ sqlalchemy/branches/schema/lib/sqlalchemy/schema.py 2006-05-08 17:12:43 UTC (rev 1424) </span><span class="lines">@@ -301,14 +301,12 @@ </span><span class="cx"> raise ArgumentError("Column may not define both index and unique") </span><span class="cx"> self._foreign_key = None </span><span class="cx"> self._original = None </span><del>- self._parent = None </del><span class="cx"> if len(kwargs): </span><span class="cx"> raise ArgumentError("Unknown arguments passed to Column: " + repr(kwargs.keys())) </span><span class="cx"> </span><span class="cx"> primary_key = util.SimpleProperty('_primary_key') </span><span class="cx"> foreign_key = util.SimpleProperty('_foreign_key') </span><span class="cx"> original = property(lambda s: s._original or s) </span><del>- parent = property(lambda s:s._parent or s) </del><span class="cx"> columns = property(lambda self:[self]) </span><span class="cx"> </span><span class="cx"> def _derived_metadata(self): </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemysqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/sql.py (1423 => 1424)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/sql.py 2006-05-08 17:10:07 UTC (rev 1423) +++ sqlalchemy/branches/schema/lib/sqlalchemy/sql.py 2006-05-08 17:12:43 UTC (rev 1424) </span><span class="lines">@@ -603,9 +603,6 @@ </span><span class="cx"> primary_key = property(lambda self:getattr(self, '_primary_key', False)) </span><span class="cx"> foreign_key = property(lambda self:getattr(self, '_foreign_key', False)) </span><span class="cx"> </span><del>- # TODO: parent can probably go away - parent = property(lambda self:getattr(self, '_parent', self), doc="the immediate parent column of this column") - </del><span class="cx"> columns = property(lambda self:[self]) </span><span class="cx"> </span><span class="cx"> def _default_orig_set(self): </span><span class="lines">@@ -1081,7 +1078,6 @@ </span><span class="cx"> </span><span class="cx"> _label = property(lambda s: s.name) </span><span class="cx"> original = property(lambda s:s.obj.original) </span><del>- parent = property(lambda s:s.obj.parent) </del><span class="cx"> def accept_visitor(self, visitor): </span><span class="cx"> self.obj.accept_visitor(visitor) </span><span class="cx"> visitor.visit_label(self) </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-05-08 17:10:37
|
<!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>[1423] sqlalchemy/branches/schema/test: got inheritance unittest in 0.2 style, some fixes to mysql</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1423</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-05-08 12:10:07 -0500 (Mon, 08 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>got inheritance unittest in 0.2 style, some fixes to mysql</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemalibsqlalchemydatabasesmysqlpy">sqlalchemy/branches/schema/lib/sqlalchemy/databases/mysql.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyenginebasepy">sqlalchemy/branches/schema/lib/sqlalchemy/engine/base.py</a></li> <li><a href="#sqlalchemybranchesschematestinheritancepy">sqlalchemy/branches/schema/test/inheritance.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschemalibsqlalchemydatabasesmysqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/databases/mysql.py (1422 => 1423)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/databases/mysql.py 2006-05-08 16:31:28 UTC (rev 1422) +++ sqlalchemy/branches/schema/lib/sqlalchemy/databases/mysql.py 2006-05-08 17:10:07 UTC (rev 1423) </span><span class="lines">@@ -6,14 +6,11 @@ </span><span class="cx"> </span><span class="cx"> import sys, StringIO, string, types, re, datetime </span><span class="cx"> </span><del>-import sqlalchemy.sql as sql -import sqlalchemy.engine as engine -import sqlalchemy.schema as schema -import sqlalchemy.ansisql as ansisql </del><ins>+from sqlalchemy import sql,engine,schema,ansisql +from sqlalchemy.engine import default </ins><span class="cx"> import sqlalchemy.types as sqltypes </span><del>-from sqlalchemy import * </del><span class="cx"> import sqlalchemy.databases.information_schema as ischema </span><del>-from sqlalchemy.exceptions import * </del><ins>+import sqlalchemy.exceptions as exceptions </ins><span class="cx"> </span><span class="cx"> try: </span><span class="cx"> import MySQLdb as mysql </span><span class="lines">@@ -26,7 +23,7 @@ </span><span class="cx"> class MSDouble(sqltypes.Numeric): </span><span class="cx"> def __init__(self, precision = None, length = None): </span><span class="cx"> if (precision is None and length is not None) or (precision is not None and length is None): </span><del>- raise ArgumentError("You must specify both precision and length or omit both altogether.") </del><ins>+ raise exceptions.ArgumentError("You must specify both precision and length or omit both altogether.") </ins><span class="cx"> super(MSDouble, self).__init__(precision, length) </span><span class="cx"> def get_col_spec(self): </span><span class="cx"> if self.precision is not None and self.length is not None: </span><span class="lines">@@ -271,7 +268,7 @@ </span><span class="cx"> if column.primary_key: </span><span class="cx"> if not override_pk: </span><span class="cx"> colspec += " PRIMARY KEY" </span><del>- if not column.foreign_key and first_pk and isinstance(column.type, types.Integer): </del><ins>+ if not column.foreign_key and first_pk and isinstance(column.type, sqltypes.Integer): </ins><span class="cx"> colspec += " AUTO_INCREMENT" </span><span class="cx"> if column.foreign_key: </span><span class="cx"> colspec += ", FOREIGN KEY (%s) REFERENCES %s(%s)" % (column.name, column.foreign_key.column.table.name, column.foreign_key.column.name) </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyenginebasepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/engine/base.py (1422 => 1423)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/engine/base.py 2006-05-08 16:31:28 UTC (rev 1422) +++ sqlalchemy/branches/schema/lib/sqlalchemy/engine/base.py 2006-05-08 17:10:07 UTC (rev 1423) </span><span class="lines">@@ -195,7 +195,7 @@ </span><span class="cx"> return Connection.executors[type(object).__mro__[-2]](self, object, *multiparams, **params) </span><span class="cx"> def execute_default(self, default, **kwargs): </span><span class="cx"> return default.accept_schema_visitor(self.engine.dialect.defaultrunner(self.engine, self.proxy, **kwargs)) </span><del>- def execute_text(self, statement, parameters): </del><ins>+ def execute_text(self, statement, parameters=None): </ins><span class="cx"> cursor = self._execute_raw(statement, parameters) </span><span class="cx"> return ResultProxy(self.engine, self, cursor) </span><span class="cx"> def _params_to_listofdicts(self, *multiparams, **params): </span></span></pre></div> <a id="sqlalchemybranchesschematestinheritancepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/test/inheritance.py (1422 => 1423)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/test/inheritance.py 2006-05-08 16:31:28 UTC (rev 1422) +++ sqlalchemy/branches/schema/test/inheritance.py 2006-05-08 17:10:07 UTC (rev 1423) </span><span class="lines">@@ -5,7 +5,9 @@ </span><span class="cx"> import sys </span><span class="cx"> </span><span class="cx"> class Principal( object ): </span><del>- pass </del><ins>+ def __init__(self, **kwargs): + for key, value in kwargs.iteritems(): + setattr(self, key, value) </ins><span class="cx"> </span><span class="cx"> class User( Principal ): </span><span class="cx"> pass </span><span class="lines">@@ -20,16 +22,18 @@ </span><span class="cx"> global users </span><span class="cx"> global groups </span><span class="cx"> global user_group_map </span><ins>+ global metadata + metadata = BoundMetaData(testbase.db) </ins><span class="cx"> principals = Table( </span><span class="cx"> 'principals', </span><del>- testbase.metadata, </del><ins>+ metadata, </ins><span class="cx"> Column('principal_id', Integer, Sequence('principal_id_seq', optional=False), primary_key=True), </span><span class="cx"> Column('name', String(50), nullable=False), </span><span class="cx"> ) </span><span class="cx"> </span><span class="cx"> users = Table( </span><span class="cx"> 'prin_users', </span><del>- testbase.metadata, </del><ins>+ metadata, </ins><span class="cx"> Column('principal_id', Integer, ForeignKey('principals.principal_id'), primary_key=True), </span><span class="cx"> Column('password', String(50), nullable=False), </span><span class="cx"> Column('email', String(50), nullable=False), </span><span class="lines">@@ -39,14 +43,14 @@ </span><span class="cx"> </span><span class="cx"> groups = Table( </span><span class="cx"> 'prin_groups', </span><del>- testbase.metadata, </del><ins>+ metadata, </ins><span class="cx"> Column( 'principal_id', Integer, ForeignKey('principals.principal_id'), primary_key=True), </span><span class="cx"> </span><span class="cx"> ) </span><span class="cx"> </span><span class="cx"> user_group_map = Table( </span><span class="cx"> 'prin_user_group_map', </span><del>- testbase.metadata, </del><ins>+ metadata, </ins><span class="cx"> Column('user_id', Integer, ForeignKey( "prin_users.principal_id"), primary_key=True ), </span><span class="cx"> Column('group_id', Integer, ForeignKey( "prin_groups.principal_id"), primary_key=True ), </span><span class="cx"> #Column('user_id', Integer, ForeignKey( "prin_users.principal_id"), ), </span><span class="lines">@@ -54,65 +58,57 @@ </span><span class="cx"> </span><span class="cx"> ) </span><span class="cx"> </span><del>- principals.create() - users.create() - groups.create() - user_group_map.create() </del><ins>+ metadata.create_all() + </ins><span class="cx"> def tearDownAll(self): </span><del>- user_group_map.drop() - groups.drop() - users.drop() - principals.drop() - testbase.metadata.tables.clear() </del><ins>+ metadata.drop_all() + </ins><span class="cx"> def setUp(self): </span><del>- objectstore.clear() </del><span class="cx"> clear_mappers() </span><span class="cx"> </span><span class="cx"> def testbasic(self): </span><del>- assign_mapper( Principal, principals ) - assign_mapper( </del><ins>+ mapper( Principal, principals ) + mapper( </ins><span class="cx"> User, </span><span class="cx"> users, </span><del>- inherits=Principal.mapper </del><ins>+ inherits=Principal </ins><span class="cx"> ) </span><span class="cx"> </span><del>- assign_mapper( </del><ins>+ mapper( </ins><span class="cx"> Group, </span><span class="cx"> groups, </span><del>- inherits=Principal.mapper, - properties=dict( users = relation(User.mapper, user_group_map, lazy=True, backref="groups") ) </del><ins>+ inherits=Principal, + properties=dict( users = relation(User, secondary=user_group_map, lazy=True, backref="groups") ) </ins><span class="cx"> ) </span><span class="cx"> </span><span class="cx"> g = Group(name="group1") </span><span class="cx"> g.users.append(User(name="user1", password="pw", email="fo...@ba...", login_id="lg1")) </span><del>- - objectstore.flush() </del><ins>+ sess = create_session() + sess.save(g) + sess.flush() </ins><span class="cx"> # TODO: put an assertion </span><span class="cx"> </span><span class="cx"> class InheritTest2(testbase.AssertMixin): </span><span class="cx"> """deals with inheritance and many-to-many relationships""" </span><span class="cx"> def setUpAll(self): </span><del>- engine = testbase.metadata - global foo, bar, foo_bar - foo = Table('foo', engine, </del><ins>+ global foo, bar, foo_bar, metadata + metadata = BoundMetaData(testbase.db) + foo = Table('foo', metadata, </ins><span class="cx"> Column('id', Integer, Sequence('foo_id_seq'), primary_key=True), </span><span class="cx"> Column('data', String(20)), </span><span class="cx"> ).create() </span><span class="cx"> </span><del>- bar = Table('bar', engine, </del><ins>+ bar = Table('bar', metadata, </ins><span class="cx"> Column('bid', Integer, ForeignKey('foo.id'), primary_key=True), </span><span class="cx"> #Column('fid', Integer, ForeignKey('foo.id'), ) </span><span class="cx"> ).create() </span><span class="cx"> </span><del>- foo_bar = Table('foo_bar', engine, </del><ins>+ foo_bar = Table('foo_bar', metadata, </ins><span class="cx"> Column('foo_id', Integer, ForeignKey('foo.id')), </span><span class="cx"> Column('bar_id', Integer, ForeignKey('bar.bid'))).create() </span><del>- </del><ins>+ metadata.create_all() </ins><span class="cx"> def tearDownAll(self): </span><del>- foo_bar.drop() - bar.drop() - foo.drop() - testbase.metadata.tables.clear() </del><ins>+ metadata.drop_all() </ins><span class="cx"> </span><span class="cx"> def testbasic(self): </span><span class="cx"> class Foo(object): </span><span class="lines">@@ -123,33 +119,28 @@ </span><span class="cx"> def __repr__(self): </span><span class="cx"> return str(self) </span><span class="cx"> </span><del>- Foo.mapper = mapper(Foo, foo) </del><ins>+ mapper(Foo, foo) </ins><span class="cx"> class Bar(Foo): </span><span class="cx"> def __str__(self): </span><span class="cx"> return "Bar(%s)" % self.data </span><span class="cx"> </span><del>- Bar.mapper = mapper(Bar, bar, inherits=Foo.mapper, properties = { - # the old way, you needed to explicitly set up a compound - # column like this. but now the mapper uses SyncRules to match up - # the parent/child inherited columns - #'id':[bar.c.bid, foo.c.id] - }) </del><ins>+ mapper(Bar, bar, inherits=Foo, properties={ + 'foos': relation(Foo, secondary=foo_bar, lazy=False) + }) + + sess = create_session() + b = Bar('barfoo', _sa_session=sess) + sess.flush() </ins><span class="cx"> </span><del>- #Bar.mapper.add_property('foos', relation(Foo.mapper, foo_bar, primaryjoin=bar.c.bid==foo_bar.c.bar_id, secondaryjoin=foo_bar.c.foo_id==foo.c.id, lazy=False)) - Bar.mapper.add_property('foos', relation(Foo.mapper, foo_bar, lazy=False)) - - b = Bar('barfoo') - objectstore.flush() - </del><span class="cx"> f1 = Foo('subfoo1') </span><span class="cx"> f2 = Foo('subfoo2') </span><span class="cx"> b.foos.append(f1) </span><span class="cx"> b.foos.append(f2) </span><span class="cx"> </span><del>- objectstore.flush() - objectstore.clear() </del><ins>+ sess.flush() + sess.clear() </ins><span class="cx"> </span><del>- l =b.mapper.select() </del><ins>+ l = sess.query(Bar).select() </ins><span class="cx"> print l[0] </span><span class="cx"> print l[0].foos </span><span class="cx"> self.assert_result(l, Bar, </span><span class="lines">@@ -160,44 +151,38 @@ </span><span class="cx"> class InheritTest3(testbase.AssertMixin): </span><span class="cx"> """deals with inheritance and many-to-many relationships""" </span><span class="cx"> def setUpAll(self): </span><del>- engine = testbase.metadata - global foo, bar, blub, bar_foo, blub_bar, blub_foo,tables - engine.engine.echo = 'debug' </del><ins>+ global foo, bar, blub, bar_foo, blub_bar, blub_foo,metadata + metadata = BoundMetaData(testbase.db) </ins><span class="cx"> # the 'data' columns are to appease SQLite which cant handle a blank INSERT </span><del>- foo = Table('foo', engine, </del><ins>+ foo = Table('foo', metadata, </ins><span class="cx"> Column('id', Integer, Sequence('foo_seq'), primary_key=True), </span><span class="cx"> Column('data', String(20))) </span><span class="cx"> </span><del>- bar = Table('bar', engine, </del><ins>+ bar = Table('bar', metadata, </ins><span class="cx"> Column('id', Integer, ForeignKey('foo.id'), primary_key=True), </span><span class="cx"> Column('data', String(20))) </span><span class="cx"> </span><del>- blub = Table('blub', engine, </del><ins>+ blub = Table('blub', metadata, </ins><span class="cx"> Column('id', Integer, ForeignKey('bar.id'), primary_key=True), </span><span class="cx"> Column('data', String(20))) </span><span class="cx"> </span><del>- bar_foo = Table('bar_foo', engine, </del><ins>+ bar_foo = Table('bar_foo', metadata, </ins><span class="cx"> Column('bar_id', Integer, ForeignKey('bar.id')), </span><span class="cx"> Column('foo_id', Integer, ForeignKey('foo.id'))) </span><span class="cx"> </span><del>- blub_bar = Table('bar_blub', engine, </del><ins>+ blub_bar = Table('bar_blub', metadata, </ins><span class="cx"> Column('blub_id', Integer, ForeignKey('blub.id')), </span><span class="cx"> Column('bar_id', Integer, ForeignKey('bar.id'))) </span><span class="cx"> </span><del>- blub_foo = Table('blub_foo', engine, </del><ins>+ blub_foo = Table('blub_foo', metadata, </ins><span class="cx"> Column('blub_id', Integer, ForeignKey('blub.id')), </span><span class="cx"> Column('foo_id', Integer, ForeignKey('foo.id'))) </span><del>- - tables = [foo, bar, blub, bar_foo, blub_bar, blub_foo] - for table in tables: - table.create() </del><ins>+ metadata.create_all() </ins><span class="cx"> def tearDownAll(self): </span><del>- for table in reversed(tables): - table.drop() - testbase.metadata.tables.clear() </del><ins>+ metadata.drop_all() </ins><span class="cx"> </span><span class="cx"> def tearDown(self): </span><del>- for table in reversed(tables): </del><ins>+ for table in metadata.table_iterator(): </ins><span class="cx"> table.delete().execute() </span><span class="cx"> </span><span class="cx"> def testbasic(self): </span><span class="lines">@@ -206,24 +191,24 @@ </span><span class="cx"> self.data = data </span><span class="cx"> def __repr__(self): </span><span class="cx"> return "Foo id %d, data %s" % (self.id, self.data) </span><del>- Foo.mapper = mapper(Foo, foo) </del><ins>+ mapper(Foo, foo) </ins><span class="cx"> </span><span class="cx"> class Bar(Foo): </span><span class="cx"> def __repr__(self): </span><span class="cx"> return "Bar id %d, data %s" % (self.id, self.data) </span><span class="cx"> </span><del>- Bar.mapper = mapper(Bar, bar, inherits=Foo.mapper, properties={ - #'foos' :relation(Foo.mapper, bar_foo, primaryjoin=bar.c.id==bar_foo.c.bar_id, lazy=False) - 'foos' :relation(Foo.mapper, bar_foo, lazy=True) </del><ins>+ mapper(Bar, bar, inherits=Foo, properties={ + 'foos' :relation(Foo, secondary=bar_foo, lazy=True) </ins><span class="cx"> }) </span><span class="cx"> </span><del>- b = Bar('bar #1') </del><ins>+ sess = create_session() + b = Bar('bar #1', _sa_session=sess) </ins><span class="cx"> b.foos.append(Foo("foo #1")) </span><span class="cx"> b.foos.append(Foo("foo #2")) </span><del>- objectstore.flush() </del><ins>+ sess.flush() </ins><span class="cx"> compare = repr(b) + repr(b.foos) </span><del>- objectstore.clear() - l = Bar.mapper.select() </del><ins>+ sess.clear() + l = sess.query(Bar).select() </ins><span class="cx"> self.echo(repr(l[0]) + repr(l[0].foos)) </span><span class="cx"> self.assert_(repr(l[0]) + repr(l[0].foos) == compare) </span><span class="cx"> </span><span class="lines">@@ -233,83 +218,66 @@ </span><span class="cx"> self.data = data </span><span class="cx"> def __repr__(self): </span><span class="cx"> return "Foo id %d, data %s" % (self.id, self.data) </span><del>- Foo.mapper = mapper(Foo, foo) </del><ins>+ mapper(Foo, foo) </ins><span class="cx"> </span><span class="cx"> class Bar(Foo): </span><span class="cx"> def __repr__(self): </span><span class="cx"> return "Bar id %d, data %s" % (self.id, self.data) </span><del>- Bar.mapper = mapper(Bar, bar, inherits=Foo.mapper) </del><ins>+ mapper(Bar, bar, inherits=Foo) </ins><span class="cx"> </span><span class="cx"> class Blub(Bar): </span><span class="cx"> def __repr__(self): </span><span class="cx"> return "Blub id %d, data %s, bars %s, foos %s" % (self.id, self.data, repr([b for b in self.bars]), repr([f for f in self.foos])) </span><span class="cx"> </span><del>- Blub.mapper = mapper(Blub, blub, inherits=Bar.mapper, properties={ -# 'bars':relation(Bar.mapper, blub_bar, primaryjoin=blub.c.id==blub_bar.c.blub_id, lazy=False), -# 'foos':relation(Foo.mapper, blub_foo, primaryjoin=blub.c.id==blub_foo.c.blub_id, lazy=False), - 'bars':relation(Bar.mapper, blub_bar, lazy=False), - 'foos':relation(Foo.mapper, blub_foo, lazy=False), </del><ins>+ mapper(Blub, blub, inherits=Bar, properties={ + 'bars':relation(Bar, secondary=blub_bar, lazy=False), + 'foos':relation(Foo, secondary=blub_foo, lazy=False), </ins><span class="cx"> }) </span><span class="cx"> </span><del>- useobjects = True - if (useobjects): - f1 = Foo("foo #1") - b1 = Bar("bar #1") - b2 = Bar("bar #2") - bl1 = Blub("blub #1") - bl1.foos.append(f1) - bl1.bars.append(b2) - objectstore.flush() - compare = repr(bl1) - blubid = bl1.id - objectstore.clear() - else: - foo.insert().execute(data='foo #1') - foo.insert().execute(data='foo #2') - bar.insert().execute(id=1, data="bar #1") - bar.insert().execute(id=2, data="bar #2") - blub.insert().execute(id=1, data="blub #1") - blub_bar.insert().execute(blub_id=1, bar_id=2) - blub_foo.insert().execute(blub_id=1, foo_id=2) </del><ins>+ sess = create_session() + f1 = Foo("foo #1", _sa_session=sess) + b1 = Bar("bar #1", _sa_session=sess) + b2 = Bar("bar #2", _sa_session=sess) + bl1 = Blub("blub #1", _sa_session=sess) + bl1.foos.append(f1) + bl1.bars.append(b2) + sess.flush() + compare = repr(bl1) + blubid = bl1.id + sess.clear() </ins><span class="cx"> </span><del>- l = Blub.mapper.select() </del><ins>+ l = sess.query(Blub).select() </ins><span class="cx"> self.echo(l) </span><span class="cx"> self.assert_(repr(l[0]) == compare) </span><del>- objectstore.clear() - x = Blub.mapper.get_by(id=blubid) #traceback 2 </del><ins>+ sess.clear() + x = sess.query(Blub).get_by(id=blubid) </ins><span class="cx"> self.echo(x) </span><span class="cx"> self.assert_(repr(x) == compare) </span><span class="cx"> </span><span class="cx"> class InheritTest4(testbase.AssertMixin): </span><span class="cx"> """deals with inheritance and one-to-many relationships""" </span><span class="cx"> def setUpAll(self): </span><del>- engine = testbase.metadata - global foo, bar, blub, tables - engine.engine.echo = 'debug' </del><ins>+ global foo, bar, blub, metadata + metadata = BoundMetaData(testbase.db) </ins><span class="cx"> # the 'data' columns are to appease SQLite which cant handle a blank INSERT </span><del>- foo = Table('foo', engine, </del><ins>+ foo = Table('foo', metadata, </ins><span class="cx"> Column('id', Integer, Sequence('foo_seq'), primary_key=True), </span><span class="cx"> Column('data', String(20))) </span><span class="cx"> </span><del>- bar = Table('bar', engine, </del><ins>+ bar = Table('bar', metadata, </ins><span class="cx"> Column('id', Integer, ForeignKey('foo.id'), primary_key=True), </span><span class="cx"> Column('data', String(20))) </span><span class="cx"> </span><del>- blub = Table('blub', engine, </del><ins>+ blub = Table('blub', metadata, </ins><span class="cx"> Column('id', Integer, ForeignKey('bar.id'), primary_key=True), </span><span class="cx"> Column('foo_id', Integer, ForeignKey('foo.id'), nullable=False), </span><span class="cx"> Column('data', String(20))) </span><del>- - tables = [foo, bar, blub] - for table in tables: - table.create() </del><ins>+ metadata.create_all() </ins><span class="cx"> def tearDownAll(self): </span><del>- for table in reversed(tables): - table.drop() - testbase.metadata.tables.clear() </del><ins>+ metadata.drop_all() </ins><span class="cx"> </span><span class="cx"> def tearDown(self): </span><del>- for table in reversed(tables): </del><ins>+ for table in metadata.table_iterator(): </ins><span class="cx"> table.delete().execute() </span><span class="cx"> </span><span class="cx"> def testbasic(self): </span><span class="lines">@@ -318,56 +286,55 @@ </span><span class="cx"> self.data = data </span><span class="cx"> def __repr__(self): </span><span class="cx"> return "Foo id %d, data %s" % (self.id, self.data) </span><del>- Foo.mapper = mapper(Foo, foo) </del><ins>+ mapper(Foo, foo) </ins><span class="cx"> </span><span class="cx"> class Bar(Foo): </span><span class="cx"> def __repr__(self): </span><span class="cx"> return "Bar id %d, data %s" % (self.id, self.data) </span><span class="cx"> </span><del>- Bar.mapper = mapper(Bar, bar, inherits=Foo.mapper) </del><ins>+ mapper(Bar, bar, inherits=Foo) </ins><span class="cx"> </span><span class="cx"> class Blub(Bar): </span><span class="cx"> def __repr__(self): </span><span class="cx"> return "Blub id %d, data %s" % (self.id, self.data) </span><span class="cx"> </span><del>- Blub.mapper = mapper(Blub, blub, inherits=Bar.mapper, properties={ - # bug was raised specifically based on the order of cols in the join.... -# 'parent_foo':relation(Foo.mapper, primaryjoin=blub.c.foo_id==foo.c.id) -# 'parent_foo':relation(Foo.mapper, primaryjoin=foo.c.id==blub.c.foo_id) - 'parent_foo':relation(Foo.mapper) </del><ins>+ mapper(Blub, blub, inherits=Bar, properties={ + 'parent_foo':relation(Foo) </ins><span class="cx"> }) </span><span class="cx"> </span><del>- b1 = Blub("blub #1") - b2 = Blub("blub #2") - f = Foo("foo #1") </del><ins>+ sess = create_session() + b1 = Blub("blub #1", _sa_session=sess) + b2 = Blub("blub #2", _sa_session=sess) + f = Foo("foo #1", _sa_session=sess) </ins><span class="cx"> b1.parent_foo = f </span><span class="cx"> b2.parent_foo = f </span><del>- objectstore.flush() </del><ins>+ sess.flush() </ins><span class="cx"> compare = repr(b1) + repr(b2) + repr(b1.parent_foo) + repr(b2.parent_foo) </span><del>- objectstore.clear() - l = Blub.mapper.select() </del><ins>+ sess.clear() + l = sess.query(Blub).select() </ins><span class="cx"> result = repr(l[0]) + repr(l[1]) + repr(l[0].parent_foo) + repr(l[1].parent_foo) </span><span class="cx"> self.echo(result) </span><span class="cx"> self.assert_(compare == result) </span><span class="cx"> self.assert_(l[0].parent_foo.data == 'foo #1' and l[1].parent_foo.data == 'foo #1') </span><span class="cx"> </span><del>-class InheritTest5(testbase.AssertMixin): </del><ins>+class InheritTest5(testbase.AssertMixin): + """testing that construction of inheriting mappers works regardless of when extra properties + are added to the superclass mapper""" </ins><span class="cx"> def setUpAll(self): </span><del>- engine = testbase.metadata - global content_type, content, product - content_type = Table('content_type', engine, </del><ins>+ global content_type, content, product, metadata + metadata = BoundMetaData(testbase.db) + content_type = Table('content_type', metadata, </ins><span class="cx"> Column('id', Integer, primary_key=True) </span><span class="cx"> ) </span><del>- content = Table('content', engine, </del><ins>+ content = Table('content', metadata, </ins><span class="cx"> Column('id', Integer, primary_key=True), </span><span class="cx"> Column('content_type_id', Integer, ForeignKey('content_type.id')) </span><span class="cx"> ) </span><del>- product = Table('product', engine, </del><ins>+ product = Table('product', metadata, </ins><span class="cx"> Column('id', Integer, ForeignKey('content.id'), primary_key=True) </span><span class="cx"> ) </span><span class="cx"> def tearDownAll(self): </span><del>- testbase.metadata.tables.clear() - </del><ins>+ pass </ins><span class="cx"> def tearDown(self): </span><span class="cx"> pass </span><span class="cx"> </span><span class="lines">@@ -385,12 +352,11 @@ </span><span class="cx"> products = mapper(Product, product, inherits=contents) </span><span class="cx"> </span><span class="cx"> def testbackref(self): </span><del>- """this test is currently known to fail in the 0.1 series of SQLAlchemy, pending the resolution of [ticket:154]""" </del><ins>+ """tests adding a property to the superclass mapper""" </ins><span class="cx"> class ContentType(object): pass </span><span class="cx"> class Content(object): pass </span><span class="cx"> class Product(Content): pass </span><span class="cx"> </span><del>- # this test fails currently </del><span class="cx"> contents = mapper(Content, content) </span><span class="cx"> products = mapper(Product, product, inherits=contents) </span><span class="cx"> content_types = mapper(ContentType, content_type, properties={ </span><span class="lines">@@ -403,20 +369,20 @@ </span><span class="cx"> """tests eager load/lazy load of child items off inheritance mappers, tests that </span><span class="cx"> LazyLoader constructs the right query condition.""" </span><span class="cx"> def setUpAll(self): </span><del>- global foo, bar, bar_foo - foo = Table('foo', testbase.metadata, Column('id', Integer, Sequence('foo_seq'), primary_key=True), - Column('data', String(30))).create() - bar = Table('bar', testbase.metadata, Column('id', Integer, ForeignKey('foo.id'), primary_key=True), - Column('data', String(30))).create() </del><ins>+ global foo, bar, bar_foo, metadata + metadata=BoundMetaData(testbase.db) + foo = Table('foo', metadata, Column('id', Integer, Sequence('foo_seq'), primary_key=True), + Column('data', String(30))) + bar = Table('bar', metadata, Column('id', Integer, ForeignKey('foo.id'), primary_key=True), + Column('data', String(30))) </ins><span class="cx"> </span><del>- bar_foo = Table('bar_foo', testbase.metadata, </del><ins>+ bar_foo = Table('bar_foo', metadata, </ins><span class="cx"> Column('bar_id', Integer, ForeignKey('bar.id')), </span><span class="cx"> Column('foo_id', Integer, ForeignKey('foo.id')) </span><del>- ).create() </del><ins>+ ) + metadata.create_all() </ins><span class="cx"> def tearDownAll(self): </span><del>- bar_foo.drop() - bar.drop() - foo.drop() </del><ins>+ metadata.drop_all() </ins><span class="cx"> </span><span class="cx"> def testbasic(self): </span><span class="cx"> class Foo(object): pass </span><span class="lines">@@ -439,9 +405,11 @@ </span><span class="cx"> </span><span class="cx"> bar_foo.insert().execute(bar_id=1, foo_id=3) </span><span class="cx"> bar_foo.insert().execute(bar_id=2, foo_id=4) </span><del>- - self.assert_(len(bars.selectfirst().lazy) == 1) - self.assert_(len(bars.selectfirst().eager) == 1) </del><ins>+ + sess = create_session() + q = sess.query(Bar) + self.assert_(len(q.selectfirst().lazy) == 1) + self.assert_(len(q.selectfirst().eager) == 1) </ins><span class="cx"> </span><span class="cx"> if __name__ == "__main__": </span><span class="cx"> testbase.main() </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-05-08 16:32:06
|
<!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>[1422] sqlalchemy/branches/schema/lib/sqlalchemy/ext/proxy.py: Fixed ProxyEngine according to the new syntax of create_engine().</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1422</dd> <dt>Author</dt> <dd>niemeyer</dd> <dt>Date</dt> <dd>2006-05-08 11:31:28 -0500 (Mon, 08 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>Fixed ProxyEngine according to the new syntax of create_engine().</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemalibsqlalchemyextproxypy">sqlalchemy/branches/schema/lib/sqlalchemy/ext/proxy.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschemalibsqlalchemyextproxypy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/ext/proxy.py (1421 => 1422)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/ext/proxy.py 2006-05-08 04:14:28 UTC (rev 1421) +++ sqlalchemy/branches/schema/lib/sqlalchemy/ext/proxy.py 2006-05-08 16:31:28 UTC (rev 1422) </span><span class="lines">@@ -9,6 +9,7 @@ </span><span class="cx"> import sqlalchemy.schema as schema </span><span class="cx"> import thread, weakref </span><span class="cx"> </span><ins>+ </ins><span class="cx"> class BaseProxyEngine(sql.Engine): </span><span class="cx"> ''' </span><span class="cx"> Basis for all proxy engines </span><span class="lines">@@ -39,29 +40,29 @@ </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><ins>+ </ins><span class="cx"> class AutoConnectEngine(BaseProxyEngine): </span><span class="cx"> ''' </span><span class="cx"> An SQLEngine proxy that automatically connects when necessary. </span><span class="cx"> ''' </span><span class="cx"> </span><del>- def __init__(self, dburi, opts=None, **kwargs): </del><ins>+ def __init__(self, dburi, **kwargs): </ins><span class="cx"> BaseProxyEngine.__init__(self) </span><del>- self.dburi= dburi - self.opts= opts - self.kwargs= kwargs - self._engine= None </del><ins>+ self.dburi = dburi + self.kwargs = kwargs + self._engine = None </ins><span class="cx"> </span><span class="cx"> def get_engine(self): </span><span class="cx"> if self._engine is None: </span><span class="cx"> if callable(self.dburi): </span><del>- dburi= self.dburi() </del><ins>+ dburi = self.dburi() </ins><span class="cx"> else: </span><del>- dburi= self.dburi - self._engine= create_engine( dburi, self.opts, **self.kwargs ) </del><ins>+ dburi = self.dburi + self._engine = create_engine(dburi, **self.kwargs) </ins><span class="cx"> return self._engine </span><span class="cx"> </span><span class="cx"> </span><del>- </del><ins>+ </ins><span class="cx"> class ProxyEngine(BaseProxyEngine): </span><span class="cx"> """ </span><span class="cx"> SQLEngine proxy. Supports lazy and late initialization by </span><span class="lines">@@ -76,14 +77,15 @@ </span><span class="cx"> self.storage.connection = {} </span><span class="cx"> self.storage.engine = None </span><span class="cx"> self.kwargs = kwargs </span><del>- - def connect(self, uri, opts=None, **kwargs): </del><ins>+ + def connect(self, *args, **kwargs): </ins><span class="cx"> """Establish connection to a real engine. </span><span class="cx"> """ </span><del>- kw = self.kwargs.copy() - kw.update(kwargs) - kwargs = kw - key = "%s(%s,%s)" % (uri, repr(opts), repr(kwargs)) </del><ins>+ kwargs.update(self.kwargs) + if not kwargs: + key = repr(args) + else: + key = "%s, %s" % (repr(args), repr(sorted(kwargs.items()))) </ins><span class="cx"> try: </span><span class="cx"> map = self.storage.connection </span><span class="cx"> except AttributeError: </span><span class="lines">@@ -93,7 +95,7 @@ </span><span class="cx"> try: </span><span class="cx"> self.engine = map[key] </span><span class="cx"> except KeyError: </span><del>- map[key] = create_engine(uri, opts, **kwargs) </del><ins>+ map[key] = create_engine(*args, **kwargs) </ins><span class="cx"> self.storage.engine = map[key] </span><span class="cx"> </span><span class="cx"> def get_engine(self): </span><span class="lines">@@ -103,5 +105,3 @@ </span><span class="cx"> </span><span class="cx"> def set_engine(self, engine): </span><span class="cx"> self.storage.engine = engine </span><del>- - </del></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-05-08 04:14:41
|
<!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>[1421] sqlalchemy/branches/schema/test: sqlite url parse fix for [ticket:174]</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1421</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-05-07 23:14:28 -0500 (Sun, 07 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>sqlite url parse fix for [ticket:174]</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemalibsqlalchemydatabasessqlitepy">sqlalchemy/branches/schema/lib/sqlalchemy/databases/sqlite.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyengineurlpy">sqlalchemy/branches/schema/lib/sqlalchemy/engine/url.py</a></li> <li><a href="#sqlalchemybranchesschematestparseconnectpy">sqlalchemy/branches/schema/test/parseconnect.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschemalibsqlalchemydatabasessqlitepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/databases/sqlite.py (1420 => 1421)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/databases/sqlite.py 2006-05-08 04:01:19 UTC (rev 1420) +++ sqlalchemy/branches/schema/lib/sqlalchemy/databases/sqlite.py 2006-05-08 04:14:28 UTC (rev 1421) </span><span class="lines">@@ -131,7 +131,7 @@ </span><span class="cx"> def schemagenerator(self, *args, **kwargs): </span><span class="cx"> return SQLiteSchemaGenerator(*args, **kwargs) </span><span class="cx"> def create_connect_args(self, url): </span><del>- filename = url.host or ':memory:' </del><ins>+ filename = url.database or ':memory:' </ins><span class="cx"> return ([filename], {}) </span><span class="cx"> def type_descriptor(self, typeobj): </span><span class="cx"> return sqltypes.adapt_type(typeobj, colspecs) </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyengineurlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/engine/url.py (1420 => 1421)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/engine/url.py 2006-05-08 04:01:19 UTC (rev 1420) +++ sqlalchemy/branches/schema/lib/sqlalchemy/engine/url.py 2006-05-08 04:14:28 UTC (rev 1421) </span><span class="lines">@@ -10,7 +10,19 @@ </span><span class="cx"> self.port = port </span><span class="cx"> self.database= database </span><span class="cx"> def __str__(self): </span><del>- return "%s:%s@%s:%s/%s" % (self.username,self.password, self.host,self.port,self.database) </del><ins>+ s = self.drivername + "://" + if self.username is not None: + s += self.username + if self.password is not None: + s += ':' + self.password + s += "@" + if self.host is not None: + s += self.host + if self.port is not None: + s += ':' + self.port + if self.database is not None: + s += '/' + self.database + return s </ins><span class="cx"> def get_module(self): </span><span class="cx"> return getattr(__import__('sqlalchemy.databases.%s' % self.drivername).databases, self.drivername) </span><span class="cx"> def translate_connect_args(self, names): </span></span></pre></div> <a id="sqlalchemybranchesschematestparseconnectpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/test/parseconnect.py (1420 => 1421)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/test/parseconnect.py 2006-05-08 04:01:19 UTC (rev 1420) +++ sqlalchemy/branches/schema/test/parseconnect.py 2006-05-08 04:14:28 UTC (rev 1421) </span><span class="lines">@@ -15,11 +15,13 @@ </span><span class="cx"> 'dbtype://hostspec', </span><span class="cx"> 'dbtype:///database', </span><span class="cx"> 'dbtype:///:memory:', </span><ins>+ 'dbtype:///foo/bar/im/a/file', + 'dbtype:///E:/work/src/LEM/db/hello.db', </ins><span class="cx"> 'dbtype://' </span><span class="cx"> ): </span><span class="cx"> u = url.make_url(text) </span><del>- # TODO: assertion conditions - print u </del><ins>+ print u, text + assert str(u) == text </ins><span class="cx"> </span><span class="cx"> </span><span class="cx"> if __name__ == "__main__": </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-05-08 04:01:42
|
<!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>[1420] sqlalchemy/branches/schema/test: column.original is being migrated to column.orig_set, which is a Set of "original" columns, 99% of the time the same as "original", except for a compositeselect in which case its the full set of proxied columns.</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1420</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-05-07 23:01:19 -0500 (Sun, 07 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>column.original is being migrated to column.orig_set, which is a Set of "original" columns, 99% of the time the same as "original", except for a compositeselect in which case its the full set of proxied columns. polymorphic column translation in Mapper now moved from key-based to column-translation based.</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemaexamplespolymorphpolymorphpy">sqlalchemy/branches/schema/examples/polymorph/polymorph.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyormmapperpy">sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyormpropertiespy">sqlalchemy/branches/schema/lib/sqlalchemy/orm/properties.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyschemapy">sqlalchemy/branches/schema/lib/sqlalchemy/schema.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemysqlpy">sqlalchemy/branches/schema/lib/sqlalchemy/sql.py</a></li> <li><a href="#sqlalchemybranchesschematestselectablepy">sqlalchemy/branches/schema/test/selectable.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschemaexamplespolymorphpolymorphpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/examples/polymorph/polymorph.py (1419 => 1420)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/examples/polymorph/polymorph.py 2006-05-06 19:55:38 UTC (rev 1419) +++ sqlalchemy/branches/schema/examples/polymorph/polymorph.py 2006-05-08 04:01:19 UTC (rev 1420) </span><span class="lines">@@ -1,5 +1,5 @@ </span><span class="cx"> from sqlalchemy import * </span><del>-import sys </del><ins>+import sys, sets </ins><span class="cx"> </span><span class="cx"> # this example illustrates a polymorphic load of two classes, where each class has a very </span><span class="cx"> # different set of properties </span><span class="lines">@@ -63,7 +63,8 @@ </span><span class="cx"> 'person':people.select(people.c.type=='person'), </span><span class="cx"> }, None, 'pjoin') </span><span class="cx"> </span><del>-person_mapper = mapper(Person, people, select_table=person_join, polymorphic_on=person_join.c.type, polymorphic_identity='person') </del><ins>+#person_mapper = mapper(Person, people, select_table=person_join, polymorphic_on=person_join.c.type, polymorphic_identity='person') +person_mapper = mapper(Person, people, select_table=person_join,polymorphic_on=person_join.c.type, polymorphic_identity='person') </ins><span class="cx"> mapper(Engineer, engineers, inherits=person_mapper, polymorphic_identity='engineer') </span><span class="cx"> mapper(Manager, managers, inherits=person_mapper, polymorphic_identity='manager') </span><span class="cx"> </span><span class="lines">@@ -71,7 +72,7 @@ </span><span class="cx"> 'employees': relation(Person, lazy=False, private=True, backref='company') </span><span class="cx"> }) </span><span class="cx"> </span><del>-session = create_session() </del><ins>+session = create_session(echo_uow=False) </ins><span class="cx"> c = Company(name='company1') </span><span class="cx"> c.employees.append(Manager(name='pointy haired boss', status='AAB', manager_name='manager1')) </span><span class="cx"> c.employees.append(Engineer(name='dilbert', status='BBA', engineer_name='engineer1', primary_language='java')) </span><span class="lines">@@ -79,14 +80,15 @@ </span><span class="cx"> c.employees.append(Engineer(name='wally', status='CGG', engineer_name='engineer2', primary_language='python')) </span><span class="cx"> c.employees.append(Manager(name='jsmith', status='ABA', manager_name='manager2')) </span><span class="cx"> session.save(c) </span><ins>+print session.new </ins><span class="cx"> session.flush() </span><del>- </del><ins>+#sys.exit() </ins><span class="cx"> session.clear() </span><span class="cx"> </span><span class="cx"> c = session.query(Company).get(1) </span><span class="cx"> for e in c.employees: </span><span class="cx"> print e, e._instance_key, e.company </span><del>- </del><ins>+assert sets.Set([e.name for e in c.employees]) == sets.Set(['pointy haired boss', 'dilbert', 'joesmith', 'wally', 'jsmith']) </ins><span class="cx"> print "\n" </span><span class="cx"> </span><span class="cx"> dilbert = session.query(Person).get_by(name='dilbert') </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyormmapperpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py (1419 => 1420)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py 2006-05-06 19:55:38 UTC (rev 1419) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py 2006-05-08 04:01:19 UTC (rev 1420) </span><span class="lines">@@ -172,7 +172,6 @@ </span><span class="cx"> # TODO: need select_table, local_table properly accounted for when custom primary key is sent </span><span class="cx"> else: </span><span class="cx"> for t in self.tables + [self.mapped_table, self.select_table]: </span><del>- print "SET UP PKS FOR ", str(t) </del><span class="cx"> try: </span><span class="cx"> l = self.pks_by_table[t] </span><span class="cx"> except KeyError: </span><span class="lines">@@ -217,6 +216,7 @@ </span><span class="cx"> # column at index 0 determines which result column is used to populate the object </span><span class="cx"> # attribute, in the case of mapping against a join with column names repeated </span><span class="cx"> # (and particularly in an inheritance relationship) </span><ins>+ # TODO: clarify this comment </ins><span class="cx"> prop.columns.insert(0, column) </span><span class="cx"> #prop.columns.append(column) </span><span class="cx"> else: </span><span class="lines">@@ -227,19 +227,8 @@ </span><span class="cx"> </span><span class="cx"> # its a ColumnProperty - match the ultimate table columns </span><span class="cx"> # back to the property </span><del>- proplist = self.columntoproperty.setdefault(column.original, []) - proplist.append(prop) - - for column in self.mapped_table.columns: - if not self.columntoproperty.has_key(column.original): - proplist = [] - self.columntoproperty[column.original] = proplist - # id like it to use this somehow - #col = self.select_table._get_col_by_original(column.original) - try: - prop = self.props[column.key] - except KeyError: - raise exceptions.ArgumentError("Selectable '%s' does not contain local table column '%s'" % (self.select_table, column.key)) </del><ins>+ for c in column.orig_set: + proplist = self.columntoproperty.setdefault(c.original, []) </ins><span class="cx"> proplist.append(prop) </span><span class="cx"> </span><span class="cx"> if not non_primary and (not mapper_registry.has_key(self.class_key) or self.is_primary or (inherits is not None and inherits._is_primary_mapper())): </span><span class="lines">@@ -374,8 +363,9 @@ </span><span class="cx"> self.props[key] = prop </span><span class="cx"> if isinstance(prop, ColumnProperty): </span><span class="cx"> for col in prop.columns: </span><del>- proplist = self.columntoproperty.setdefault(col.original, []) - proplist.append(prop) </del><ins>+ for c in col.orig_set: + proplist = self.columntoproperty.setdefault(c.original, []) + proplist.append(prop) </ins><span class="cx"> </span><span class="cx"> if init: </span><span class="cx"> prop.init(key, self) </span><span class="lines">@@ -864,10 +854,9 @@ </span><span class="cx"> bare keynames to accomplish this. So far this works for the various polymorphic </span><span class="cx"> examples.""" </span><span class="cx"> newrow = util.DictDecorator(row) </span><del>- for c in self.select_table.c: - newrow[c.name] = row[c] </del><span class="cx"> for c in tomapper.select_table.c: </span><del>- newrow[c] = newrow[c.name] </del><ins>+ c2 = self.select_table._get_col_by_original(c) + newrow[c] = row[c2] </ins><span class="cx"> return newrow </span><span class="cx"> </span><span class="cx"> def populate_instance(self, session, instance, row, identitykey, imap, isnew, frommapper=None): </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyormpropertiespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/properties.py (1419 => 1420)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/properties.py 2006-05-06 19:55:38 UTC (rev 1419) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/properties.py 2006-05-08 04:01:19 UTC (rev 1420) </span><span class="lines">@@ -609,7 +609,7 @@ </span><span class="cx"> return map.keys() </span><span class="cx"> map = {} </span><span class="cx"> for c in self.eagertarget.c: </span><del>- parent = self.target._get_col_by_original(c.original) </del><ins>+ parent = self.target._get_col_by_original(c) </ins><span class="cx"> map[parent] = c </span><span class="cx"> map[parent._label] = c </span><span class="cx"> map[parent.name] = c </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyschemapy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/schema.py (1419 => 1420)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/schema.py 2006-05-06 19:55:38 UTC (rev 1419) +++ sqlalchemy/branches/schema/lib/sqlalchemy/schema.py 2006-05-08 04:01:19 UTC (rev 1420) </span><span class="lines">@@ -300,14 +300,14 @@ </span><span class="cx"> if self.index is not None and self.unique is not None: </span><span class="cx"> raise ArgumentError("Column may not define both index and unique") </span><span class="cx"> self._foreign_key = None </span><del>- self._orig = None </del><ins>+ self._original = None </ins><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><span class="cx"> </span><span class="cx"> primary_key = util.SimpleProperty('_primary_key') </span><span class="cx"> foreign_key = util.SimpleProperty('_foreign_key') </span><del>- original = property(lambda s: s._orig or s) </del><ins>+ original = property(lambda s: s._original or s) </ins><span class="cx"> parent = property(lambda s:s._parent or s) </span><span class="cx"> columns = property(lambda self:[self]) </span><span class="cx"> </span><span class="lines">@@ -366,7 +366,8 @@ </span><span class="cx"> fk = self.foreign_key.copy() </span><span class="cx"> c = Column(name or self.name, self.type, fk, self.default, key = name or self.key, primary_key = self.primary_key, nullable = self.nullable, hidden = self.hidden) </span><span class="cx"> c.table = selectable </span><del>- c._orig = self.original </del><ins>+ c._original = self.original + c._orig_set = self.orig_set </ins><span class="cx"> c._parent = self </span><span class="cx"> if not c.hidden: </span><span class="cx"> selectable.columns[c.key] = c </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemysqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/sql.py (1419 => 1420)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/sql.py 2006-05-06 19:55:38 UTC (rev 1419) +++ sqlalchemy/branches/schema/lib/sqlalchemy/sql.py 2006-05-08 04:01:19 UTC (rev 1420) </span><span class="lines">@@ -8,7 +8,7 @@ </span><span class="cx"> </span><span class="cx"> from sqlalchemy import util, exceptions </span><span class="cx"> from sqlalchemy import types as sqltypes </span><del>-import string, re, random </del><ins>+import string, re, random, sets </ins><span class="cx"> types = __import__('types') </span><span class="cx"> </span><span class="cx"> __all__ = ['text', 'table', 'column', 'func', 'select', 'update', 'insert', 'delete', 'join', 'and_', 'or_', 'not_', 'between_', 'cast', 'union', 'union_all', 'null', 'desc', 'asc', 'outerjoin', 'alias', 'subquery', 'literal', 'bindparam', 'exists'] </span><span class="lines">@@ -602,9 +602,22 @@ </span><span class="cx"> of the single column, providing the same list-based interface as a FromClause.""" </span><span class="cx"> primary_key = property(lambda self:getattr(self, '_primary_key', False)) </span><span class="cx"> foreign_key = property(lambda self:getattr(self, '_foreign_key', False)) </span><del>- original = property(lambda self:getattr(self, '_original', self)) - parent = property(lambda self:getattr(self, '_parent', self)) </del><ins>+ + # TODO: parent can probably go away + parent = property(lambda self:getattr(self, '_parent', self), doc="the immediate parent column of this column") + </ins><span class="cx"> columns = property(lambda self:[self]) </span><ins>+ + def _default_orig_set(self): + try: + return self._orig_set + except AttributeError: + self._orig_set = sets.Set([self.original]) + return self._orig_set + # TODO: merge orig_set and original into just one Set + orig_set = property(_default_orig_set, doc="""a Set containing Table-bound, non-proxied ColumnElements for which this ColumnElement is a proxy. In all cases except for a column proxied from a Union (i.e. CompoundSelect), this set will be just one element.""") + original = property(lambda self:getattr(self, '_original', self), doc="Scalar version of orig_set, which is usually one element. For a column proxied through a CompoundSelect, this will be just one of the columns in orig_set.") + </ins><span class="cx"> def _make_proxy(self, selectable, name=None): </span><span class="cx"> """creates a new ColumnElement representing this ColumnElement as it appears in the select list </span><span class="cx"> of an enclosing selectable. The default implementation returns a ColumnClause if a name is given, </span><span class="lines">@@ -613,6 +626,8 @@ </span><span class="cx"> select list of an enclosing selectable.""" </span><span class="cx"> if name is not None: </span><span class="cx"> co = ColumnClause(name, selectable) </span><ins>+ co._original = self + co._orig_set = self.orig_set </ins><span class="cx"> selectable.columns[name]= co </span><span class="cx"> return co </span><span class="cx"> else: </span><span class="lines">@@ -645,17 +660,18 @@ </span><span class="cx"> self._oid_column = self._locate_oid_column() </span><span class="cx"> return self._oid_column </span><span class="cx"> def _get_col_by_original(self, column, raiseerr=True): </span><del>- """given a column which is a ColumnClause object attached to a TableClause object - (i.e. an "original" column), return the Column object from this - Selectable which corresponds to that original Column, or None if this Selectable - does not contain the column.""" - try: - return self.original_columns[column.original] - except KeyError: </del><ins>+ """given a ColumnElement, return the ColumnElement object from this + Selectable which corresponds to that original Column via a proxy relationship.""" + for c in column.orig_set: + try: + return self.original_columns[c] + except KeyError: + pass + else: </ins><span class="cx"> if not raiseerr: </span><span class="cx"> return None </span><span class="cx"> else: </span><del>- raise exceptions.InvalidRequestError("cant get orig for " + str(column) + " with table " + column.table.name + " from table " + self.name) </del><ins>+ raise exceptions.InvalidRequestError("cant get orig for " + str(column) + " with table " + str(column.table.name) + " from table " + str(self.name)) </ins><span class="cx"> </span><span class="cx"> def _get_exported_attribute(self, name): </span><span class="cx"> try: </span><span class="lines">@@ -667,10 +683,12 @@ </span><span class="cx"> c = property(lambda s:s._get_exported_attribute('_columns')) </span><span class="cx"> primary_key = property(lambda s:s._get_exported_attribute('_primary_key')) </span><span class="cx"> foreign_keys = property(lambda s:s._get_exported_attribute('_foreign_keys')) </span><del>- original_columns = property(lambda s:s._get_exported_attribute('_orig_cols')) </del><ins>+ original_columns = property(lambda s:s._get_exported_attribute('_orig_cols'), doc="a dictionary mapping an original Table-bound column to a proxied column in this FromClause.") </ins><span class="cx"> oid_column = property(_get_oid_column) </span><span class="cx"> </span><span class="cx"> def _export_columns(self): </span><ins>+ """this method is called the first time any of the "exported attrbutes" are called. it receives from the Selectable + a list of all columns to be exported and creates "proxy" columns for each one.""" </ins><span class="cx"> if hasattr(self, '_columns'): </span><span class="cx"> # TODO: put a mutex here ? this is a key place for threading probs </span><span class="cx"> return </span><span class="lines">@@ -683,7 +701,8 @@ </span><span class="cx"> if column.is_selectable(): </span><span class="cx"> for co in column.columns: </span><span class="cx"> cp = self._proxy_column(co) </span><del>- self._orig_cols[co.original] = cp </del><ins>+ for ci in cp.orig_set: + self._orig_cols[ci] = cp </ins><span class="cx"> if self.oid_column is not None: </span><span class="cx"> self._orig_cols[self.oid_column.original] = self.oid_column </span><span class="cx"> def _exportable_columns(self): </span><span class="lines">@@ -939,7 +958,6 @@ </span><span class="cx"> def __init__(self, left, right, onclause=None, isouter = False): </span><span class="cx"> self.left = left </span><span class="cx"> self.right = right </span><del>- </del><span class="cx"> # TODO: if no onclause, do NATURAL JOIN </span><span class="cx"> if onclause is None: </span><span class="cx"> self.onclause = self._match_primaries(left, right) </span><span class="lines">@@ -947,6 +965,7 @@ </span><span class="cx"> self.onclause = onclause </span><span class="cx"> self.isouter = isouter </span><span class="cx"> </span><ins>+ name = property(lambda s: "Join object on " + s.left.name + " " + s.right.name) </ins><span class="cx"> def _locate_oid_column(self): </span><span class="cx"> return self.left.oid_column </span><span class="cx"> </span><span class="lines">@@ -1034,6 +1053,7 @@ </span><span class="cx"> return None </span><span class="cx"> </span><span class="cx"> def _exportable_columns(self): </span><ins>+ #return self.selectable._exportable_columns() </ins><span class="cx"> return self.selectable.columns </span><span class="cx"> </span><span class="cx"> def accept_visitor(self, visitor): </span><span class="lines">@@ -1110,6 +1130,7 @@ </span><span class="cx"> def _make_proxy(self, selectable, name = None): </span><span class="cx"> c = ColumnClause(name or self.name, selectable, hidden=self.hidden) </span><span class="cx"> c._original = self.original </span><ins>+ c._orig_set = self.orig_set </ins><span class="cx"> if not self.hidden: </span><span class="cx"> selectable.columns[c.name] = c </span><span class="cx"> return c </span><span class="lines">@@ -1193,6 +1214,8 @@ </span><span class="cx"> </span><span class="cx"> class SelectBaseMixin(object): </span><span class="cx"> """base class for Select and CompoundSelects""" </span><ins>+ def __init__(self): + self.name = None </ins><span class="cx"> def order_by(self, *clauses): </span><span class="cx"> if len(clauses) == 1 and clauses[0] is None: </span><span class="cx"> self.order_by_clause = ClauseList() </span><span class="lines">@@ -1217,6 +1240,7 @@ </span><span class="cx"> </span><span class="cx"> class CompoundSelect(SelectBaseMixin, FromClause): </span><span class="cx"> def __init__(self, keyword, *selects, **kwargs): </span><ins>+ SelectBaseMixin.__init__(self) </ins><span class="cx"> self.keyword = keyword </span><span class="cx"> self.selects = selects </span><span class="cx"> self.use_labels = kwargs.pop('use_labels', False) </span><span class="lines">@@ -1228,7 +1252,7 @@ </span><span class="cx"> s.order_by(None) </span><span class="cx"> self.group_by(*kwargs.get('group_by', [None])) </span><span class="cx"> self.order_by(*kwargs.get('order_by', [None])) </span><del>- </del><ins>+ self._col_map = {} </ins><span class="cx"> def _locate_oid_column(self): </span><span class="cx"> return self.selects[0].oid_column </span><span class="cx"> </span><span class="lines">@@ -1239,10 +1263,19 @@ </span><span class="cx"> </span><span class="cx"> def _proxy_column(self, column): </span><span class="cx"> if self.use_labels: </span><del>- return column._make_proxy(self, name=column._label) </del><ins>+ col = column._make_proxy(self, name=column._label) </ins><span class="cx"> else: </span><del>- return column._make_proxy(self, name=column.name) </del><ins>+ col = column._make_proxy(self, name=column.name) </ins><span class="cx"> </span><ins>+ try: + colset = self._col_map[col.name] + except KeyError: + colset = sets.Set() + self._col_map[col.name] = colset + [colset.add(c) for c in col.orig_set] + col._orig_set = colset + return col + </ins><span class="cx"> def accept_visitor(self, visitor): </span><span class="cx"> self.order_by_clause.accept_visitor(visitor) </span><span class="cx"> self.group_by_clause.accept_visitor(visitor) </span><span class="lines">@@ -1261,9 +1294,9 @@ </span><span class="cx"> """represents a SELECT statement, with appendable clauses, as well as </span><span class="cx"> the ability to execute itself and return a result set.""" </span><span class="cx"> def __init__(self, columns=None, whereclause = None, from_obj = [], order_by = None, group_by=None, having=None, use_labels = False, distinct=False, for_update=False, engine=None, limit=None, offset=None, scalar=False, correlate=True): </span><ins>+ SelectBaseMixin.__init__(self) </ins><span class="cx"> self._froms = util.OrderedDict() </span><span class="cx"> self.use_labels = use_labels </span><del>- self.name = None </del><span class="cx"> self.whereclause = None </span><span class="cx"> self.having = None </span><span class="cx"> self._engine = engine </span><span class="lines">@@ -1350,8 +1383,6 @@ </span><span class="cx"> def _exportable_columns(self): </span><span class="cx"> return self._raw_columns </span><span class="cx"> def _proxy_column(self, column): </span><del>- if column.name == 'oid': - raise "hi" </del><span class="cx"> if self.use_labels: </span><span class="cx"> return column._make_proxy(self, name=column._label) </span><span class="cx"> else: </span></span></pre></div> <a id="sqlalchemybranchesschematestselectablepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/test/selectable.py (1419 => 1420)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/test/selectable.py 2006-05-06 19:55:38 UTC (rev 1419) +++ sqlalchemy/branches/schema/test/selectable.py 2006-05-08 04:01:19 UTC (rev 1420) </span><span class="lines">@@ -15,6 +15,7 @@ </span><span class="cx"> Column('col1', Integer, primary_key=True), </span><span class="cx"> Column('col2', String(20)), </span><span class="cx"> Column('col3', Integer), </span><ins>+ Column('colx', Integer), </ins><span class="cx"> redefine=True </span><span class="cx"> ) </span><span class="cx"> </span><span class="lines">@@ -22,6 +23,7 @@ </span><span class="cx"> Column('col1', Integer, primary_key=True), </span><span class="cx"> Column('col2', Integer, ForeignKey('table1.col1')), </span><span class="cx"> Column('col3', String(20)), </span><ins>+ Column('coly', Integer), </ins><span class="cx"> redefine=True </span><span class="cx"> ) </span><span class="cx"> </span><span class="lines">@@ -36,6 +38,53 @@ </span><span class="cx"> print str(j) </span><span class="cx"> self.assert_(criterion.compare(j.onclause)) </span><span class="cx"> </span><ins>+ def testunion(self): + # tests that we can correspond a column in a Select statement with a certain Table, against + # a column in a Union where one of its underlying Selects matches to that same Table + u = select([table.c.col1, table.c.col2, table.c.col3, table.c.colx, null().label('coly')]).union( + select([table2.c.col1, table2.c.col2, table2.c.col3, null().label('colx'), table2.c.coly]) + ) + s1 = table.select(use_labels=True) + s2 = table2.select(use_labels=True) + print ["%d %s" % (id(c),c.key) for c in u.c] + c = u._get_col_by_original(s1.c.table1_col2) + print "%d %s" % (id(c), c.key) + assert u._get_col_by_original(s1.c.table1_col2) is u.c.col2 + assert u._get_col_by_original(s2.c.table2_col2) is u.c.col2 + + def testaliasunion(self): + # same as testunion, except its an alias of the union + u = select([table.c.col1, table.c.col2, table.c.col3, table.c.colx, null().label('coly')]).union( + select([table2.c.col1, table2.c.col2, table2.c.col3, null().label('colx'), table2.c.coly]) + ).alias('analias') + s1 = table.select(use_labels=True) + s2 = table2.select(use_labels=True) + print ["%d %s" % (id(c),c.key) for c in u.c] +# c = u._get_col_by_original(s1.c.table1_col2) + print "%d %s" % (id(c), c.key) + assert u._get_col_by_original(s1.c.table1_col2) is u.c.col2 + assert u._get_col_by_original(s2.c.table2_col2) is u.c.col2 + + def testselectunion(self): + # like testaliasunion, but off a Select off the union. + u = select([table.c.col1, table.c.col2, table.c.col3, table.c.colx, null().label('coly')]).union( + select([table2.c.col1, table2.c.col2, table2.c.col3, null().label('colx'), table2.c.coly]) + ).alias('analias') + s = select([u]) + s1 = table.select(use_labels=True) + s2 = table2.select(use_labels=True) + assert s._get_col_by_original(s1.c.table1_col2) is s.c.col2 + assert s._get_col_by_original(s2.c.table2_col2) is s.c.col2 + + def testunionagainstjoin(self): + # same as testunion, except its an alias of the union + u = select([table.c.col1, table.c.col2, table.c.col3, table.c.colx, null().label('coly')]).union( + select([table2.c.col1, table2.c.col2, table2.c.col3, null().label('colx'), table2.c.coly]) + ).alias('analias') + j1 = table.join(table2) + assert u._get_col_by_original(j1.c.table1_colx) is u.c.colx + assert j1._get_col_by_original(u.c.colx) is j1.c.table1_colx + </ins><span class="cx"> def testjoin(self): </span><span class="cx"> a = join(table, table2) </span><span class="cx"> print str(a.select(use_labels=True)) </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-05-06 19:55:48
|
<!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>[1419] sqlalchemy/branches/schema/lib/sqlalchemy/orm: working on export of union'ed columns...</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1419</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-05-06 14:55:38 -0500 (Sat, 06 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>working on export of union'ed columns...</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemalibsqlalchemyormmapperpy">sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyormunitofworkpy">sqlalchemy/branches/schema/lib/sqlalchemy/orm/unitofwork.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschemalibsqlalchemyormmapperpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py (1418 => 1419)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py 2006-05-06 18:52:03 UTC (rev 1418) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py 2006-05-06 19:55:38 UTC (rev 1419) </span><span class="lines">@@ -169,8 +169,10 @@ </span><span class="cx"> if k.table != self.mapped_table: </span><span class="cx"> # associate pk cols from subtables to the "main" table </span><span class="cx"> self.pks_by_table.setdefault(self.mapped_table, util.HashSet(ordered=True)).append(k) </span><ins>+ # TODO: need select_table, local_table properly accounted for when custom primary key is sent </ins><span class="cx"> else: </span><span class="cx"> for t in self.tables + [self.mapped_table, self.select_table]: </span><ins>+ print "SET UP PKS FOR ", str(t) </ins><span class="cx"> try: </span><span class="cx"> l = self.pks_by_table[t] </span><span class="cx"> except KeyError: </span><span class="lines">@@ -228,6 +230,18 @@ </span><span class="cx"> proplist = self.columntoproperty.setdefault(column.original, []) </span><span class="cx"> proplist.append(prop) </span><span class="cx"> </span><ins>+ for column in self.mapped_table.columns: + if not self.columntoproperty.has_key(column.original): + proplist = [] + self.columntoproperty[column.original] = proplist + # id like it to use this somehow + #col = self.select_table._get_col_by_original(column.original) + try: + prop = self.props[column.key] + except KeyError: + raise exceptions.ArgumentError("Selectable '%s' does not contain local table column '%s'" % (self.select_table, column.key)) + proplist.append(prop) + </ins><span class="cx"> if not non_primary and (not mapper_registry.has_key(self.class_key) or self.is_primary or (inherits is not None and inherits._is_primary_mapper())): </span><span class="cx"> sessionlib.global_attributes.reset_class_managed(self.class_) </span><span class="cx"> self._init_class() </span><span class="lines">@@ -546,9 +560,10 @@ </span><span class="cx"> an UPDATE statement for each table used by this mapper, for each element of the </span><span class="cx"> list.""" </span><span class="cx"> </span><ins>+ #print "SAVE_OBJ MAPPER", self.class_.__name__, objects </ins><span class="cx"> connection = uow.transaction.connection(self) </span><span class="cx"> for table in self.tables: </span><del>- #print "SAVE_OBJ table ", table.name </del><ins>+ #print "SAVE_OBJ table ", self.class_.__name__, table.name </ins><span class="cx"> # looping through our set of tables, which are all "real" tables, as opposed </span><span class="cx"> # to our main table which might be a select statement or something non-writeable </span><span class="cx"> </span><span class="lines">@@ -557,6 +572,7 @@ </span><span class="cx"> # they are separate execs via execute(), not executemany() </span><span class="cx"> </span><span class="cx"> if not self._has_pks(table): </span><ins>+ #print "NO PKS ?", str(table) </ins><span class="cx"> # if we dont have a full set of primary keys for this table, we cant really </span><span class="cx"> # do any CRUD with it, so skip. this occurs if we are mapping against a query </span><span class="cx"> # that joins on other tables so its not really an error condition. </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyormunitofworkpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/unitofwork.py (1418 => 1419)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/unitofwork.py 2006-05-06 18:52:03 UTC (rev 1418) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/unitofwork.py 2006-05-06 19:55:38 UTC (rev 1419) </span><span class="lines">@@ -742,7 +742,7 @@ </span><span class="cx"> def _repr_task(task): </span><span class="cx"> if task.mapper is not None: </span><span class="cx"> if task.mapper.__class__.__name__ == 'Mapper': </span><del>- name = task.mapper.class_.__name__ + "/" + str(task.mapper.primarytable) + "/" + str(id(task.mapper)) </del><ins>+ name = task.mapper.class_.__name__ + "/" + str(task.mapper.local_table) + "/" + str(id(task.mapper)) </ins><span class="cx"> else: </span><span class="cx"> name = repr(task.mapper) </span><span class="cx"> else: </span><span class="lines">@@ -815,7 +815,7 @@ </span><span class="cx"> def __repr__(self): </span><span class="cx"> if self.mapper is not None: </span><span class="cx"> if self.mapper.__class__.__name__ == 'Mapper': </span><del>- name = self.mapper.class_.__name__ + "/" + self.mapper.primarytable.name </del><ins>+ name = self.mapper.class_.__name__ + "/" + self.mapper.local_table.name </ins><span class="cx"> else: </span><span class="cx"> name = repr(self.mapper) </span><span class="cx"> else: </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-05-06 18:52:16
|
<!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>[1418] sqlalchemy/branches/schema/lib/sqlalchemy: polymorph tweaks</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1418</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-05-06 13:52:03 -0500 (Sat, 06 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>polymorph tweaks</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemaexamplespolymorphpolymorphpy">sqlalchemy/branches/schema/examples/polymorph/polymorph.py</a></li> <li><a href="#sqlalchemybranchesschemaexamplespolymorphsinglepy">sqlalchemy/branches/schema/examples/polymorph/single.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyormpropertiespy">sqlalchemy/branches/schema/lib/sqlalchemy/orm/properties.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyschemapy">sqlalchemy/branches/schema/lib/sqlalchemy/schema.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschemaexamplespolymorphpolymorphpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/examples/polymorph/polymorph.py (1417 => 1418)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/examples/polymorph/polymorph.py 2006-05-06 18:28:48 UTC (rev 1417) +++ sqlalchemy/branches/schema/examples/polymorph/polymorph.py 2006-05-06 18:52:03 UTC (rev 1418) </span><span class="lines">@@ -4,35 +4,36 @@ </span><span class="cx"> # this example illustrates a polymorphic load of two classes, where each class has a very </span><span class="cx"> # different set of properties </span><span class="cx"> </span><del>-db = create_engine('sqlite://', echo='debug', echo_uow=False) </del><ins>+metadata = BoundMetaData('sqlite://', echo='debug') </ins><span class="cx"> </span><span class="cx"> # a table to store companies </span><del>-companies = Table('companies', db, </del><ins>+companies = Table('companies', metadata, </ins><span class="cx"> Column('company_id', Integer, primary_key=True), </span><del>- Column('name', String(50))).create() </del><ins>+ Column('name', String(50))) </ins><span class="cx"> </span><span class="cx"> # we will define an inheritance relationship between the table "people" and "engineers", </span><span class="cx"> # and a second inheritance relationship between the table "people" and "managers" </span><del>-people = Table('people', db, </del><ins>+people = Table('people', metadata, </ins><span class="cx"> Column('person_id', Integer, primary_key=True), </span><span class="cx"> Column('company_id', Integer, ForeignKey('companies.company_id')), </span><span class="cx"> Column('name', String(50)), </span><del>- Column('type', String(30))).create() </del><ins>+ Column('type', String(30))) </ins><span class="cx"> </span><del>-engineers = Table('engineers', db, </del><ins>+engineers = Table('engineers', metadata, </ins><span class="cx"> Column('person_id', Integer, ForeignKey('people.person_id'), primary_key=True), </span><span class="cx"> Column('status', String(30)), </span><span class="cx"> Column('engineer_name', String(50)), </span><span class="cx"> Column('primary_language', String(50)), </span><del>- ).create() </del><ins>+ ) </ins><span class="cx"> </span><del>-managers = Table('managers', db, </del><ins>+managers = Table('managers', metadata, </ins><span class="cx"> Column('person_id', Integer, ForeignKey('people.person_id'), primary_key=True), </span><span class="cx"> Column('status', String(30)), </span><span class="cx"> Column('manager_name', String(50)) </span><del>- ).create() </del><ins>+ ) + +metadata.create_all() </ins><span class="cx"> </span><del>- </del><span class="cx"> # create our classes. The Engineer and Manager classes extend from Person. </span><span class="cx"> class Person(object): </span><span class="cx"> def __init__(self, **kwargs): </span><span class="lines">@@ -54,8 +55,7 @@ </span><span class="cx"> return "Company %s" % self.name </span><span class="cx"> </span><span class="cx"> </span><del>-# create a union that represents both types of joins. we have to use -# nulls to pad out the disparate columns. </del><ins>+# create a union that represents both types of joins. </ins><span class="cx"> person_join = polymorphic_union( </span><span class="cx"> { </span><span class="cx"> 'engineer':people.join(engineers), </span><span class="lines">@@ -68,7 +68,7 @@ </span><span class="cx"> mapper(Manager, managers, inherits=person_mapper, polymorphic_identity='manager') </span><span class="cx"> </span><span class="cx"> mapper(Company, companies, properties={ </span><del>- 'employees': relation(Person, lazy=True, private=True, backref='company') </del><ins>+ 'employees': relation(Person, lazy=False, private=True, backref='company') </ins><span class="cx"> }) </span><span class="cx"> </span><span class="cx"> session = create_session() </span><span class="lines">@@ -105,7 +105,4 @@ </span><span class="cx"> session.delete(c) </span><span class="cx"> session.flush() </span><span class="cx"> </span><del>-managers.drop() -engineers.drop() -people.drop() -companies.drop() </del><ins>+metadata.drop_all() </ins></span></pre></div> <a id="sqlalchemybranchesschemaexamplespolymorphsinglepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/examples/polymorph/single.py (1417 => 1418)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/examples/polymorph/single.py 2006-05-06 18:28:48 UTC (rev 1417) +++ sqlalchemy/branches/schema/examples/polymorph/single.py 2006-05-06 18:52:03 UTC (rev 1418) </span><span class="lines">@@ -1,25 +1,85 @@ </span><span class="cx"> from sqlalchemy import * </span><span class="cx"> </span><del>-metadata = MetaData() </del><ins>+metadata = BoundMetaData('sqlite://', echo='debug') </ins><span class="cx"> </span><ins>+# a table to store companies +companies = Table('companies', metadata, + Column('company_id', Integer, primary_key=True), + Column('name', String(50))) + </ins><span class="cx"> employees_table = Table('employees', metadata, </span><span class="cx"> Column('employee_id', Integer, primary_key=True), </span><ins>+ Column('company_id', Integer, ForeignKey('companies.company_id')), </ins><span class="cx"> Column('name', String(50)), </span><del>- Column('type', String(20)) </del><ins>+ Column('type', String(20)), + Column('engineer_name', String(50)), + Column('primary_language', String(50)), + Column('manager_name', String(50)) </ins><span class="cx"> ) </span><span class="cx"> </span><del>-engine = create_engine('sqlite:///') -metadata.create_all(engine) </del><ins>+metadata.create_all() </ins><span class="cx"> </span><del>-class Employee(object): - pass - -class Manager(Employee): - pass - -class Engineer(Employee): - pass </del><ins>+class Person(object): + def __init__(self, **kwargs): + for key, value in kwargs.iteritems(): + setattr(self, key, value) + def __repr__(self): + return "Ordinary person %s" % self.name +class Engineer(Person): + def __repr__(self): + return "Engineer %s, status %s, engineer_name %s, primary_language %s" % (self.name, self.status, self.engineer_name, self.primary_language) +class Manager(Person): + def __repr__(self): + return "Manager %s, status %s, manager_name %s" % (self.name, self.status, self.manager_name) +class Company(object): + def __init__(self, **kwargs): + for key, value in kwargs.iteritems(): + setattr(self, key, value) + def __repr__(self): + return "Company %s" % self.name </ins><span class="cx"> </span><del>-employee_mapper = mapper(Employee, employees_table, polymorphic_on=employees_table.c.type) </del><ins>+person_mapper = mapper(Person, employees_table, polymorphic_on=employees_table.c.type, polymorphic_identity='person') </ins><span class="cx"> manager_mapper = mapper(Manager, inherits=employee_mapper, polymorphic_identity='manager') </span><span class="cx"> engineer_mapper = mapper(Engineer, inherits=employee_mapper, polymorphic_identity='engineer') </span><ins>+ + + +mapper(Company, companies, properties={ + 'employees': relation(Person, lazy=True, private=True, backref='company') +}) + +session = create_session() +c = Company(name='company1') +c.employees.append(Manager(name='pointy haired boss', status='AAB', manager_name='manager1')) +c.employees.append(Engineer(name='dilbert', status='BBA', engineer_name='engineer1', primary_language='java')) +c.employees.append(Person(name='joesmith', status='HHH')) +c.employees.append(Engineer(name='wally', status='CGG', engineer_name='engineer2', primary_language='python')) +c.employees.append(Manager(name='jsmith', status='ABA', manager_name='manager2')) +session.save(c) +session.flush() + +session.clear() + +c = session.query(Company).get(1) +for e in c.employees: + print e, e._instance_key, e.company + +print "\n" + +dilbert = session.query(Person).get_by(name='dilbert') +dilbert2 = session.query(Engineer).get_by(name='dilbert') +assert dilbert is dilbert2 + +dilbert.engineer_name = 'hes dibert!' + +session.flush() +session.clear() + +c = session.query(Company).get(1) +for e in c.employees: + print e, e._instance_key + +session.delete(c) +session.flush() + +metadata.drop_all() </ins></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyormpropertiespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/properties.py (1417 => 1418)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/properties.py 2006-05-06 18:28:48 UTC (rev 1417) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/properties.py 2006-05-06 18:52:03 UTC (rev 1418) </span><span class="lines">@@ -584,18 +584,18 @@ </span><span class="cx"> </span><span class="cx"> if not self.uselist: </span><span class="cx"> if isnew: </span><del>- h.setattr_clean(self._instance(session, row, imap)) </del><ins>+ h.setattr_clean(self.mapper._instance(session, decorated_row, imap, None)) </ins><span class="cx"> else: </span><span class="cx"> # call _instance on the row, even though the object has been created, </span><span class="cx"> # so that we further descend into properties </span><del>- self._instance(session, row, imap) </del><ins>+ self.mapper._instance(session, decorated_row, imap, None) </ins><span class="cx"> </span><span class="cx"> return </span><span class="cx"> elif isnew: </span><span class="cx"> result_list = h </span><span class="cx"> else: </span><span class="cx"> result_list = getattr(instance, self.key) </span><del>- self._instance(session, row, imap, result_list) </del><ins>+ self.mapper._instance(session, decorated_row, imap, result_list) </ins><span class="cx"> </span><span class="cx"> def _create_decorator_row(self): </span><span class="cx"> class DecoratorDict(object): </span><span class="lines">@@ -629,10 +629,6 @@ </span><span class="cx"> self._create_eager_chain() </span><span class="cx"> return self._row_decorator(row) </span><span class="cx"> </span><del>- def _instance(self, session, row, imap, result_list=None): - """gets an instance from a row, via this EagerLoader's mapper.""" - return self.mapper._instance(session, self._decorate_row(row), imap, result_list) - </del><span class="cx"> class GenericOption(mapper.MapperOption): </span><span class="cx"> """a mapper option that can handle dotted property names, </span><span class="cx"> descending down through the relations of a mapper until it </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyschemapy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/schema.py (1417 => 1418)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/schema.py 2006-05-06 18:28:48 UTC (rev 1417) +++ sqlalchemy/branches/schema/lib/sqlalchemy/schema.py 2006-05-06 18:52:03 UTC (rev 1418) </span><span class="lines">@@ -15,6 +15,7 @@ </span><span class="cx"> </span><span class="cx"> """ </span><span class="cx"> from sqlalchemy import sql, types, exceptions,util </span><ins>+import sqlalchemy </ins><span class="cx"> import copy, re, string </span><span class="cx"> </span><span class="cx"> __all__ = ['SchemaItem', 'Table', 'Column', 'ForeignKey', 'Sequence', 'Index', </span></span></pre> </div> </div> </body> </html> |
<!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>[1417] sqlalchemy/branches/schema/test: eager loader extends lazyloader, will degrade to a lazy load upon execute if primary key columns arent present in the row (i.e.</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1417</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-05-06 13:28:48 -0500 (Sat, 06 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>eager loader extends lazyloader, will degrade to a lazy load upon execute if primary key columns arent present in the row (i.e. not just None). allows alternate select statements to be plugged into a mapper without eager loads breaking</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemalibsqlalchemyormmapperpy">sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyormpropertiespy">sqlalchemy/branches/schema/lib/sqlalchemy/orm/properties.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyschemapy">sqlalchemy/branches/schema/lib/sqlalchemy/schema.py</a></li> <li><a href="#sqlalchemybranchesschematestmapperpy">sqlalchemy/branches/schema/test/mapper.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschemalibsqlalchemyormmapperpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py (1416 => 1417)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py 2006-05-06 18:12:19 UTC (rev 1416) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py 2006-05-06 18:28:48 UTC (rev 1417) </span><span class="lines">@@ -762,7 +762,7 @@ </span><span class="cx"> for c in prop.cascade_iterator(type, object, recursive): </span><span class="cx"> yield c </span><span class="cx"> </span><del>- def _identity_key(self, row): </del><ins>+ def _row_identity_key(self, row): </ins><span class="cx"> return sessionlib.get_row_key(row, self.class_, self.pks_by_table[self.select_table], self.entity_name) </span><span class="cx"> </span><span class="cx"> def _instance(self, session, row, imap, result = None, populate_existing = False): </span><span class="lines">@@ -784,7 +784,7 @@ </span><span class="cx"> # been exposed to being modified by the application. </span><span class="cx"> </span><span class="cx"> populate_existing = populate_existing or self.always_refresh </span><del>- identitykey = self._identity_key(row) </del><ins>+ identitykey = self._row_identity_key(row) </ins><span class="cx"> if session.has_key(identitykey): </span><span class="cx"> instance = session._get(identitykey) </span><span class="cx"> isnew = False </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyormpropertiespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/properties.py (1416 => 1417)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/properties.py 2006-05-06 18:12:19 UTC (rev 1416) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/properties.py 2006-05-06 18:28:48 UTC (rev 1417) </span><span class="lines">@@ -448,9 +448,11 @@ </span><span class="cx"> return (lazywhere, binds, reverse) </span><span class="cx"> </span><span class="cx"> </span><del>-class EagerLoader(PropertyLoader): </del><ins>+class EagerLoader(LazyLoader): </ins><span class="cx"> """loads related objects inline with a parent query.""" </span><span class="cx"> def do_init_subclass(self, key, parent, recursion_stack=None): </span><ins>+ if recursion_stack is None: + LazyLoader.do_init_subclass(self, key, parent) </ins><span class="cx"> parent._has_eager = True </span><span class="cx"> </span><span class="cx"> self.eagertarget = self.target.alias() </span><span class="lines">@@ -566,6 +568,15 @@ </span><span class="cx"> """receive a row. tell our mapper to look for a new object instance in the row, and attach </span><span class="cx"> it to a list on the parent instance.""" </span><span class="cx"> </span><ins>+ decorated_row = self._decorate_row(row) + try: + # check for identity key + identity_key = self.mapper._row_identity_key(decorated_row) + except KeyError: + # else degrade to a lazy loader + LazyLoader.execute(self, session, instance, row, identitykey, imap, isnew) + return + </ins><span class="cx"> if isnew: </span><span class="cx"> # new row loaded from the database. initialize a blank container on the instance. </span><span class="cx"> # this will override any per-class lazyloading type of stuff. </span><span class="lines">@@ -603,9 +614,8 @@ </span><span class="cx"> map[parent._label] = c </span><span class="cx"> map[parent.name] = c </span><span class="cx"> return DecoratorDict </span><del>- - def _instance(self, session, row, imap, result_list=None): - """gets an instance from a row, via this EagerLoader's mapper.""" </del><ins>+ + def _decorate_row(self, row): </ins><span class="cx"> # since the EagerLoader makes an Alias of its mapper's table, </span><span class="cx"> # we translate the actual result columns back to what they </span><span class="cx"> # would normally be into a "virtual row" which is passed to the child mapper. </span><span class="lines">@@ -613,9 +623,16 @@ </span><span class="cx"> # (neither do any MapperExtensions). The row is keyed off the Column object </span><span class="cx"> # (which is what mappers use) as well as its "label" (which might be what </span><span class="cx"> # user-defined code is using) </span><del>- row = self._row_decorator(row) - return self.mapper._instance(session, row, imap, result_list) </del><ins>+ try: + return self._row_decorator(row) + except AttributeError: + self._create_eager_chain() + return self._row_decorator(row) </ins><span class="cx"> </span><ins>+ def _instance(self, session, row, imap, result_list=None): + """gets an instance from a row, via this EagerLoader's mapper.""" + return self.mapper._instance(session, self._decorate_row(row), imap, result_list) + </ins><span class="cx"> class GenericOption(mapper.MapperOption): </span><span class="cx"> """a mapper option that can handle dotted property names, </span><span class="cx"> descending down through the relations of a mapper until it </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyschemapy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/schema.py (1416 => 1417)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/schema.py 2006-05-06 18:12:19 UTC (rev 1416) +++ sqlalchemy/branches/schema/lib/sqlalchemy/schema.py 2006-05-06 18:28:48 UTC (rev 1417) </span><span class="lines">@@ -395,10 +395,10 @@ </span><span class="cx"> object representing the relationship, or just its string name given as </span><span class="cx"> "tablename.columnname". schema can be specified as </span><span class="cx"> "schema.tablename.columnname" """ </span><ins>+ if isinstance(column, unicode): + column = str(column) </ins><span class="cx"> self._colspec = column </span><span class="cx"> self._column = None </span><del>- if isinstance(column, unicode): - column = str(column) </del><span class="cx"> </span><span class="cx"> def __repr__(self): </span><span class="cx"> return "ForeignKey(%s)" % repr(self._get_colspec()) </span></span></pre></div> <a id="sqlalchemybranchesschematestmapperpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/test/mapper.py (1416 => 1417)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/test/mapper.py 2006-05-06 18:12:19 UTC (rev 1416) +++ sqlalchemy/branches/schema/test/mapper.py 2006-05-06 18:28:48 UTC (rev 1417) </span><span class="lines">@@ -283,6 +283,27 @@ </span><span class="cx"> self.assert_result(l, User, *user_address_result) </span><span class="cx"> self.assert_sql_count(db, go, 0) </span><span class="cx"> </span><ins>+ def testeagerdegrade(self): + """tests that an eager relation automatically degrades to a lazy relation if eager columns are not available""" + sess = create_session() + usermapper = mapper(User, users, properties = dict( + addresses = relation(mapper(Address, addresses), lazy = False) + )) + + # first test straight eager load, 1 statement + def go(): + l = usermapper.query(sess).select() + self.assert_result(l, User, *user_address_result) + self.assert_sql_count(db, go, 1) + + # then select just from users. run it into instances. + # then assert the data, which will launch 3 more lazy loads + def go(): + r = users.select().execute() + l = usermapper.instances(r, sess) + self.assert_result(l, User, *user_address_result) + self.assert_sql_count(db, go, 4) + </ins><span class="cx"> def testlazyoptions(self): </span><span class="cx"> """tests that an eager relation can be upgraded to a lazy relation via the options method""" </span><span class="cx"> sess = create_session() </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-05-06 18:12:31
|
<!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>[1416] sqlalchemy/trunk/lib/sqlalchemy/schema.py: had unicode check improperly placed</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1416</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-05-06 13:12:19 -0500 (Sat, 06 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>had unicode check improperly placed</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunklibsqlalchemyschemapy">sqlalchemy/trunk/lib/sqlalchemy/schema.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunklibsqlalchemyschemapy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/schema.py (1415 => 1416)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/schema.py 2006-05-06 15:54:03 UTC (rev 1415) +++ sqlalchemy/trunk/lib/sqlalchemy/schema.py 2006-05-06 18:12:19 UTC (rev 1416) </span><span class="lines">@@ -404,10 +404,11 @@ </span><span class="cx"> object representing the relationship, or just its string name given as </span><span class="cx"> "tablename.columnname". schema can be specified as </span><span class="cx"> "schemaname.tablename.columnname" """ </span><ins>+ if isinstance(column, unicode): + column = str(column) </ins><span class="cx"> self._colspec = column </span><span class="cx"> self._column = None </span><del>- if isinstance(column, unicode): - column = str(column) </del><ins>+ </ins><span class="cx"> def __repr__(self): </span><span class="cx"> return "ForeignKey(%s)" % repr(self._get_colspec()) </span><span class="cx"> </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-05-06 15:54:12
|
<!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>[1415] sqlalchemy/branches/schema/doc/build/content/pooling.myt: removed old myt file</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1415</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-05-06 10:54:03 -0500 (Sat, 06 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>removed old myt file</pre> <h3>Removed Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemadocbuildcontentpoolingmyt">sqlalchemy/branches/schema/doc/build/content/pooling.myt</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschemadocbuildcontentpoolingmyt"></a> <div class="delfile"><h4>Deleted: sqlalchemy/branches/schema/doc/build/content/pooling.myt (1414 => 1415)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/doc/build/content/pooling.myt 2006-05-06 15:52:24 UTC (rev 1414) +++ sqlalchemy/branches/schema/doc/build/content/pooling.myt 2006-05-06 15:54:03 UTC (rev 1415) </span><span class="lines">@@ -1,87 +0,0 @@ </span><del>-<%flags>inherit='document_base.myt'</%flags> -<%attr>title='Connection Pooling'</%attr> -<!-- WARNING! This file was automatically generated. - Modify .txt file if need you to change the content.--> -<&|doclib.myt:item, name="pooling", description="Connection Pooling"&> - -<p>This section describes the connection pool module of SQLAlchemy. The <code>Pool</code> object it provides is normally embedded within an <code>Engine</code> instance. For most cases, explicit access to the pool module is not required. However, the <code>Pool</code> object can be used on its own, without the rest of SA, to manage DBAPI connections; this section describes that usage. Also, this section will describe in more detail how to customize the pooling strategy used by an <code>Engine</code>. -</p> -<p>At the base of any database helper library is a system of efficiently acquiring connections to the database. Since the establishment of a database connection is typically a somewhat expensive operation, an application needs a way to get at database connections repeatedly without incurring the full overhead each time. Particularly for server-side web applications, a connection pool is the standard way to maintain a "pool" of database connections which are used over and over again among many requests. Connection pools typically are configured to maintain a certain "size", which represents how many connections can be used simultaneously without resorting to creating more newly-established connections. -</p> - -<&|doclib.myt:item, name="establishing", description="Establishing a Transparent Connection Pool"&> - -<p>Any DBAPI module can be "proxied" through the connection pool using the following technique (note that the usage of 'psycopg2' is <strong>just an example</strong>; substitute whatever DBAPI module you'd like): -</p> -<&|formatting.myt:code, use_sliders="True", syntaxtype="python"&> import sqlalchemy.pool as pool - import psycopg2 as psycopg - psycopg = pool.manage(psycopg) - - # then connect normally - connection = psycopg.connect(database='test', username='scott', password='tiger') - </&><p>This produces a <code>sqlalchemy.pool.DBProxy</code> object which supports the same <code>connect()</code> function as the original DBAPI module. Upon connection, a thread-local connection proxy object is returned, which delegates its calls to a real DBAPI connection object. This connection object is stored persistently within a connection pool (an instance of <code>sqlalchemy.pool.Pool</code>) that corresponds to the exact connection arguments sent to the <code>connect()</code> function. The connection proxy also returns a proxied cursor object upon calling <code>connection.cursor()</code>. When all cursors as well as the connection proxy are de-referenced, the connection is automatically made available again by the owning pool object. -</p> -<p>Basically, the <code>connect()</code> function is used in its usual way, and the pool module transparently returns thread-local pooled connections. Each distinct set of connect arguments corresponds to a brand new connection pool created; in this way, an application can maintain connections to multiple schemas and/or databases, and each unique connect argument set will be managed by a different pool object. -</p> - -</&> -<&|doclib.myt:item, name="configuration", description="Connection Pool Configuration"&> - -<p>When proxying a DBAPI module through the <code>pool</code> module, options exist for how the connections should be pooled: -</p> -<ul> - <li> - echo=False : if set to True, connections being pulled and retrieved from/to the pool will be logged to the standard output, as well as pool sizing information. - </li> - - <li> - use_threadlocal=True : if set to True, repeated calls to connect() within the same application thread will be guaranteed to return the <strong>same</strong> connection object, if one has already been retrieved from the pool and has not been returned yet. This allows code to retrieve a connection from the pool, and then while still holding on to that connection, to call other functions which also ask the pool for a connection of the same arguments; those functions will act upon the same connection that the calling method is using. Note that once the connection is returned to the pool, it then may be used by another thread. To guarantee a single unique connection per thread that <strong>never</strong> changes, use the option <code>poolclass=SingletonThreadPool</code>, in which case the use_threadlocal parameter is automatically set to False. - </li> - - <li> - poolclass=QueuePool : the Pool class used by the pool module to provide pooling. QueuePool uses the Python <code>Queue.Queue</code> class to maintain a list of available connections. A developer can supply his or her own Pool class to supply a different pooling algorithm. Also included is the <code>SingletonThreadPool</code>, which provides a single distinct connection per thread and is required with SQLite. - </li> - - <li> - pool_size=5 : used by <code>QueuePool</code> - the size of the pool to be maintained. This is the largest number of connections that will be kept persistently in the pool. Note that the pool begins with no connections; once this number of connections is requested, that number of connections will remain. - </li> - - <li> - max_overflow=10 : used by <code>QueuePool</code> - the maximum overflow size of the pool. When the number of checked-out connections reaches the size set in pool_size, additional connections will be returned up to this limit. When those additional connections are returned to the pool, they are disconnected and discarded. It follows then that the total number of simultaneous connections the pool will allow is <code>pool_size</code> + <code>max_overflow</code>, and the total number of "sleeping" connections the pool will allow is <code>pool_size</code>. <code>max_overflow</code> can be set to -1 to indicate no overflow limit; no limit will be placed on the total number of concurrent connections. - </li> - - <li> - timeout=30 : used by <code>QueuePool</code> - the timeout before giving up on returning a connection, if none are available and the <code>max_overflow</code> has been reached. - </li> -</ul> - -</&> -<&|doclib.myt:item, name="custom", description="Custom Pool Construction"&> - -<p>One level below using a DBProxy to make transparent pools is creating the pool yourself. The pool module comes with two implementations of connection pools: <code>QueuePool</code> and <code>SingletonThreadPool</code>. While <code>QueuePool</code> uses <code>Queue.Queue</code> to provide connections, <code>SingletonThreadPool</code> provides a single per-thread connection which SQLite requires. -</p> -<p>Constructing your own pool involves passing a callable used to create a connection. Through this method, custom connection schemes can be made, such as a connection that automatically executes some initialization commands to start. The options from the previous section can be used as they apply to <code>QueuePool</code> or <code>SingletonThreadPool</code>. -</p> -<&|formatting.myt:code, use_sliders="True", syntaxtype="python", title="Plain QueuePool"&> import sqlalchemy.pool as pool - import psycopg2 - - def getconn(): - c = psycopg2.connect(username='ed', host='127.0.0.1', dbname='test') - # execute an initialization function on the connection before returning - c.cursor.execute("setup_encodings()") - return c - - p = pool.QueuePool(getconn, max_overflow=10, pool_size=5, use_threadlocal=True) - </&><p>Or with SingletonThreadPool: -</p> -<&|formatting.myt:code, use_sliders="True", syntaxtype="python", title="SingletonThreadPool"&> import sqlalchemy.pool as pool - import sqlite - - def getconn(): - return sqlite.connect(filename='myfile.db') - - # SQLite connections require the SingletonThreadPool - p = pool.SingletonThreadPool(getconn) - </&> -</&> -</&> </del></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-05-06 15:52:42
|
<!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>[1414] sqlalchemy/branches/schema/doc/build/content: added two more txt files</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1414</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-05-06 10:52:24 -0500 (Sat, 06 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>added two more txt files</pre> <h3>Added Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemadocbuildcontentpoolingtxt">sqlalchemy/branches/schema/doc/build/content/pooling.txt</a></li> <li><a href="#sqlalchemybranchesschemadocbuildcontentthreadlocaltxt">sqlalchemy/branches/schema/doc/build/content/threadlocal.txt</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschemadocbuildcontentpoolingtxt"></a> <div class="addfile"><h4>Added: sqlalchemy/branches/schema/doc/build/content/pooling.txt (1413 => 1414)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/doc/build/content/pooling.txt 2006-05-06 02:14:41 UTC (rev 1413) +++ sqlalchemy/branches/schema/doc/build/content/pooling.txt 2006-05-06 15:52:24 UTC (rev 1414) </span><span class="lines">@@ -0,0 +1,65 @@ </span><ins>+Connection Pooling {@name=pooling} +====================== + +This section describes the connection pool module of SQLAlchemy. The `Pool` object it provides is normally embedded within an `Engine` instance. For most cases, explicit access to the pool module is not required. However, the `Pool` object can be used on its own, without the rest of SA, to manage DBAPI connections; this section describes that usage. Also, this section will describe in more detail how to customize the pooling strategy used by an `Engine`. + +At the base of any database helper library is a system of efficiently acquiring connections to the database. Since the establishment of a database connection is typically a somewhat expensive operation, an application needs a way to get at database connections repeatedly without incurring the full overhead each time. Particularly for server-side web applications, a connection pool is the standard way to maintain a "pool" of database connections which are used over and over again among many requests. Connection pools typically are configured to maintain a certain "size", which represents how many connections can be used simultaneously without resorting to creating more newly-established connections. + +### Establishing a Transparent Connection Pool {@name=establishing} + +Any DBAPI module can be "proxied" through the connection pool using the following technique (note that the usage of 'psycopg2' is **just an example**; substitute whatever DBAPI module you'd like): + + {python} + import sqlalchemy.pool as pool + import psycopg2 as psycopg + psycopg = pool.manage(psycopg) + + # then connect normally + connection = psycopg.connect(database='test', username='scott', password='tiger') + +This produces a `sqlalchemy.pool.DBProxy` object which supports the same `connect()` function as the original DBAPI module. Upon connection, a thread-local connection proxy object is returned, which delegates its calls to a real DBAPI connection object. This connection object is stored persistently within a connection pool (an instance of `sqlalchemy.pool.Pool`) that corresponds to the exact connection arguments sent to the `connect()` function. The connection proxy also returns a proxied cursor object upon calling `connection.cursor()`. When all cursors as well as the connection proxy are de-referenced, the connection is automatically made available again by the owning pool object. + +Basically, the `connect()` function is used in its usual way, and the pool module transparently returns thread-local pooled connections. Each distinct set of connect arguments corresponds to a brand new connection pool created; in this way, an application can maintain connections to multiple schemas and/or databases, and each unique connect argument set will be managed by a different pool object. + +### Connection Pool Configuration {@name=configuration} + +When proxying a DBAPI module through the `pool` module, options exist for how the connections should be pooled: + +* echo=False : if set to True, connections being pulled and retrieved from/to the pool will be logged to the standard output, as well as pool sizing information. +* use\_threadlocal=True : if set to True, repeated calls to connect() within the same application thread will be guaranteed to return the **same** connection object, if one has already been retrieved from the pool and has not been returned yet. This allows code to retrieve a connection from the pool, and then while still holding on to that connection, to call other functions which also ask the pool for a connection of the same arguments; those functions will act upon the same connection that the calling method is using. Note that once the connection is returned to the pool, it then may be used by another thread. To guarantee a single unique connection per thread that **never** changes, use the option `poolclass=SingletonThreadPool`, in which case the use_threadlocal parameter is automatically set to False. +* poolclass=QueuePool : the Pool class used by the pool module to provide pooling. QueuePool uses the Python `Queue.Queue` class to maintain a list of available connections. A developer can supply his or her own Pool class to supply a different pooling algorithm. Also included is the `SingletonThreadPool`, which provides a single distinct connection per thread and is required with SQLite. +* pool\_size=5 : used by `QueuePool` - the size of the pool to be maintained. This is the largest number of connections that will be kept persistently in the pool. Note that the pool begins with no connections; once this number of connections is requested, that number of connections will remain. +* max\_overflow=10 : used by `QueuePool` - the maximum overflow size of the pool. When the number of checked-out connections reaches the size set in pool_size, additional connections will be returned up to this limit. When those additional connections are returned to the pool, they are disconnected and discarded. It follows then that the total number of simultaneous connections the pool will allow is `pool_size` + `max_overflow`, and the total number of "sleeping" connections the pool will allow is `pool_size`. `max_overflow` can be set to -1 to indicate no overflow limit; no limit will be placed on the total number of concurrent connections. +* timeout=30 : used by `QueuePool` - the timeout before giving up on returning a connection, if none are available and the `max_overflow` has been reached. + + +### Custom Pool Construction {@name=custom} + +One level below using a DBProxy to make transparent pools is creating the pool yourself. The pool module comes with two implementations of connection pools: `QueuePool` and `SingletonThreadPool`. While `QueuePool` uses `Queue.Queue` to provide connections, `SingletonThreadPool` provides a single per-thread connection which SQLite requires. + +Constructing your own pool involves passing a callable used to create a connection. Through this method, custom connection schemes can be made, such as a connection that automatically executes some initialization commands to start. The options from the previous section can be used as they apply to `QueuePool` or `SingletonThreadPool`. + + {python title="Plain QueuePool"} + import sqlalchemy.pool as pool + import psycopg2 + + def getconn(): + c = psycopg2.connect(username='ed', host='127.0.0.1', dbname='test') + # execute an initialization function on the connection before returning + c.cursor.execute("setup_encodings()") + return c + + p = pool.QueuePool(getconn, max_overflow=10, pool_size=5, use_threadlocal=True) + +Or with SingletonThreadPool: + + {python title="SingletonThreadPool"} + import sqlalchemy.pool as pool + import sqlite + + def getconn(): + return sqlite.connect(filename='myfile.db') + + # SQLite connections require the SingletonThreadPool + p = pool.SingletonThreadPool(getconn) + </ins></span></pre></div> <a id="sqlalchemybranchesschemadocbuildcontentthreadlocaltxt"></a> <div class="addfile"><h4>Added: sqlalchemy/branches/schema/doc/build/content/threadlocal.txt (1413 => 1414)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/doc/build/content/threadlocal.txt 2006-05-06 02:14:41 UTC (rev 1413) +++ sqlalchemy/branches/schema/doc/build/content/threadlocal.txt 2006-05-06 15:52:24 UTC (rev 1414) </span><span class="lines">@@ -0,0 +1,2 @@ </span><ins>+The threadlocal mod {@name=threadlocal} +============ </ins></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-05-06 02:14:50
|
<!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>[1413] sqlalchemy/branches/schema/lib/sqlalchemy/orm/session.py: connection() takes class_or_mapper</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1413</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-05-05 21:14:41 -0500 (Fri, 05 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>connection() takes class_or_mapper</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemalibsqlalchemyormsessionpy">sqlalchemy/branches/schema/lib/sqlalchemy/orm/session.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschemalibsqlalchemyormsessionpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/session.py (1412 => 1413)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/session.py 2006-05-06 02:14:06 UTC (rev 1412) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/session.py 2006-05-06 02:14:41 UTC (rev 1413) </span><span class="lines">@@ -15,10 +15,12 @@ </span><span class="cx"> self.connections = {} </span><span class="cx"> self.parent = parent </span><span class="cx"> self.autoflush = autoflush </span><del>- def connection(self, mapper): </del><ins>+ def connection(self, mapper_or_class, entity_name=None): + if isinstance(mapper_or_class, type): + mapper_or_class = class_mapper(mapper_or_class, entity_name=entity_name) </ins><span class="cx"> if self.parent is not None: </span><del>- return self.parent.connection(mapper) - engine = self.session.get_bind(mapper) </del><ins>+ return self.parent.connection(mapper_or_class) + engine = self.session.get_bind(mapper_or_class) </ins><span class="cx"> return self.get_or_add(engine) </span><span class="cx"> def _begin(self): </span><span class="cx"> return SessionTransaction(self.session, self) </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-05-06 02:14:21
|
<!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>[1412] sqlalchemy/branches/schema/doc/build/content: edits</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1412</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-05-05 21:14:06 -0500 (Fri, 05 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>edits</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemadocbuildcontentadv_datamappingtxt">sqlalchemy/branches/schema/doc/build/content/adv_datamapping.txt</a></li> <li><a href="#sqlalchemybranchesschemadocbuildcontentdatamappingtxt">sqlalchemy/branches/schema/doc/build/content/datamapping.txt</a></li> <li><a href="#sqlalchemybranchesschemadocbuildcontentdbenginetxt">sqlalchemy/branches/schema/doc/build/content/dbengine.txt</a></li> <li><a href="#sqlalchemybranchesschemadocbuildcontentmetadatatxt">sqlalchemy/branches/schema/doc/build/content/metadata.txt</a></li> <li><a href="#sqlalchemybranchesschemadocbuildcontentsqlconstructiontxt">sqlalchemy/branches/schema/doc/build/content/sqlconstruction.txt</a></li> <li><a href="#sqlalchemybranchesschemadocbuildcontentunitofworktxt">sqlalchemy/branches/schema/doc/build/content/unitofwork.txt</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschemadocbuildcontentadv_datamappingtxt"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/doc/build/content/adv_datamapping.txt (1411 => 1412)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/doc/build/content/adv_datamapping.txt 2006-05-06 00:54:41 UTC (rev 1411) +++ sqlalchemy/branches/schema/doc/build/content/adv_datamapping.txt 2006-05-06 02:14:06 UTC (rev 1412) </span><span class="lines">@@ -363,7 +363,7 @@ </span><span class="cx"> </span><span class="cx"> Without polymorphic loading, you just define a separate mapper for each class. </span><span class="cx"> </span><del>- {python} </del><ins>+ {python title="Concrete Inheritance, Non-polymorphic"} </ins><span class="cx"> managers_table = Table('managers', metadata, </span><span class="cx"> Column('employee_id', Integer, primary_key=True), </span><span class="cx"> Column('name', String(50)), </span><span class="lines">@@ -381,7 +381,7 @@ </span><span class="cx"> </span><span class="cx"> With polymorphic loading, the SQL query to do the actual polymorphic load must be constructed, usually as a UNION. There is a helper function to create these UNIONS called `polymorphic_union`. </span><span class="cx"> </span><del>- {python} </del><ins>+ {python title="Concrete Inheritance, Polymorphic"} </ins><span class="cx"> pjoin = polymorphic_union({ </span><span class="cx"> 'manager':managers_table, </span><span class="cx"> 'engineer':engineers_table </span><span class="lines">@@ -395,7 +395,9 @@ </span><span class="cx"> </span><span class="cx"> #### Multiple Table Inheritance </span><span class="cx"> </span><del>- {python} </del><ins>+Like concrete table inheritance, this can be done non-polymorphically, or with a little more complexity, polymorphically: + + {python title="Multiple Table Inheritance, Non-polymorphic"} </ins><span class="cx"> people = Table('people', metadata, </span><span class="cx"> Column('person_id', Integer, primary_key=True), </span><span class="cx"> Column('name', String(50)), </span><span class="lines">@@ -411,6 +413,13 @@ </span><span class="cx"> Column('manager_data', String(50)), </span><span class="cx"> ) </span><span class="cx"> </span><ins>+ person_mapper = mapper(Person, people) + mapper(Engineer, engineers, inherits=person_mapper) + mapper(Manager, managers, inherits=person_mapper) + +Polymorphic: + + {python title="Multiple Table Inheritance, Polymorphic"} </ins><span class="cx"> person_join = polymorphic_union( </span><span class="cx"> { </span><span class="cx"> 'engineer':people.join(engineers), </span><span class="lines">@@ -422,7 +431,7 @@ </span><span class="cx"> mapper(Engineer, engineers, inherits=person_mapper, polymorphic_identity='engineer') </span><span class="cx"> mapper(Manager, managers, inherits=person_mapper, polymorphic_identity='manager') </span><span class="cx"> </span><del>-The join condition in an inheritance relationship can be specified explicitly, using `inherit_condition`: </del><ins>+The join condition in a multiple table inheritance relationship can be specified explicitly, using `inherit_condition`: </ins><span class="cx"> </span><span class="cx"> {python} </span><span class="cx"> AddressUser.mapper = mapper( </span><span class="lines">@@ -652,11 +661,11 @@ </span><span class="cx"> </span><span class="cx"> Other arguments not covered above include: </span><span class="cx"> </span><del>-* select_table=None - often used with polymorphic mappers, this is a `Selectable` which will take the place of the `Mapper`'s main table argument when performing queries. -* version_id_col=None - an integer-holding Column object that will be assigned an incrementing </del><ins>+* select\_table=None - often used with polymorphic mappers, this is a `Selectable` which will take the place of the `Mapper`'s main table argument when performing queries. +* version\_id\_col=None - an integer-holding Column object that will be assigned an incrementing </ins><span class="cx"> counter, which is added to the WHERE clause used by UPDATE and DELETE statements. The matching row </span><span class="cx"> count returned by the database is compared to the expected row count, and an exception is raised if they dont match. This is a basic "optimistic concurrency" check. Without the version id column, SQLAlchemy still compares the updated rowcount. </span><del>-* always_refresh=False - this option will cause the mapper to refresh all the attributes of all objects loaded by select/get statements, regardless of if they already exist in the current session. this includes all lazy- and eager-loaded relationship attributes, and will also overwrite any changes made to attributes on the column. </del><ins>+* always\_refresh=False - this option will cause the mapper to refresh all the attributes of all objects loaded by select/get statements, regardless of if they already exist in the current session. this includes all lazy- and eager-loaded relationship attributes, and will also overwrite any changes made to attributes on the column. </ins><span class="cx"> </span><span class="cx"> ### Extending Mapper {@name=extending} </span><span class="cx"> </span></span></pre></div> <a id="sqlalchemybranchesschemadocbuildcontentdatamappingtxt"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/doc/build/content/datamapping.txt (1411 => 1412)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/doc/build/content/datamapping.txt 2006-05-06 00:54:41 UTC (rev 1411) +++ sqlalchemy/branches/schema/doc/build/content/datamapping.txt 2006-05-06 02:14:06 UTC (rev 1412) </span><span class="lines">@@ -364,7 +364,7 @@ </span><span class="cx"> </span><span class="cx"> # select users where username is 'jane', get the first element of the list </span><span class="cx"> # this will incur a load operation for the parent table </span><del>- {sql}user = session.query(User).select(user_name='jane')[0] </del><ins>+ {sql}user = session.query(User).select_by(user_name='jane')[0] </ins><span class="cx"> SELECT users.user_id AS users_user_id, </span><span class="cx"> users.user_name AS users_user_name, users.password AS users_password </span><span class="cx"> FROM users WHERE users.user_name = :users_user_name ORDER BY users.oid </span><span class="lines">@@ -378,8 +378,9 @@ </span><span class="cx"> addresses.city AS addresses_city, addresses.state AS addresses_state, </span><span class="cx"> addresses.zip AS addresses_zip FROM addresses </span><span class="cx"> WHERE addresses.user_id = :users_user_id ORDER BY addresses.oid </span><del>- {'users_user_id': 1} - print repr(a) </del><ins>+ {'users_user_id': 1} + + print repr(a) </ins><span class="cx"> </span><span class="cx"> ##### Useful Feature: Creating Joins via select_by {@name=relselectby} </span><span class="cx"> </span><span class="lines">@@ -405,7 +406,7 @@ </span><span class="cx"> </span><span class="cx"> #### Selecting from Relationships: Eager Load {@name=eagerload} </span><span class="cx"> </span><del>-With just a single parameter "lazy=False" specified to the relation object, the parent and child SQL queries can be joined together. </del><ins>+With just a single parameter `lazy=False` specified to the relation object, the parent and child SQL queries can be joined together. </ins><span class="cx"> </span><span class="cx"> {python} </span><span class="cx"> mapper(Address, addresses_table) </span><span class="lines">@@ -447,7 +448,7 @@ </span><span class="cx"> WHERE addresses.street = :addresses_street AND users.user_id = addresses.user_id ORDER BY users.oid, addresses_6ca7.oid </span><span class="cx"> {'addresses_street': '123 Green Street'} </span><span class="cx"> </span><del>-The join implied by passing the "street" parameter is converted into an "aliasized" clause by the eager loader, so that it does not conflict with the join used to eager load the child address objects. </del><ins>+The join implied by passing the "street" parameter is stated as an *additional* join between the `addresses` and `users` tables. Also, since the eager join is "aliasized", no name conflict occurs. </ins><span class="cx"> </span><span class="cx"> #### Switching Lazy/Eager, No Load {@name=options} </span><span class="cx"> </span></span></pre></div> <a id="sqlalchemybranchesschemadocbuildcontentdbenginetxt"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/doc/build/content/dbengine.txt (1411 => 1412)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/doc/build/content/dbengine.txt 2006-05-06 00:54:41 UTC (rev 1411) +++ sqlalchemy/branches/schema/doc/build/content/dbengine.txt 2006-05-06 02:14:06 UTC (rev 1412) </span><span class="lines">@@ -20,14 +20,13 @@ </span><span class="cx"> </span><span class="cx"> ### Supported Databases {@name=supported} </span><span class="cx"> </span><del>-Engines exist for SQLite, Postgres, MySQL, MS-SQL, and Oracle, using the Pysqlite, Psycopg (1 or 2), MySQLDB, adodbapi or pymssql, and cx_Oracle modules. There is also not-well tested support for Firebird. For each engine, a distinct Python module exists in the `sqlalchemy.databases` package, which provides implementations of some of the objects mentioned in the previous section. </del><ins>+Engines exist for SQLite, Postgres, MySQL, and Oracle, using the Pysqlite, Psycopg (1 or 2), MySQLDB, and cx_Oracle modules. There is also preliminary support for MS-SQL using adodbapi or pymssql, as well as Firebird. For each engine, a distinct Python module exists in the `sqlalchemy.databases` package, which provides implementations of some of the objects mentioned in the previous section. </ins><span class="cx"> </span><span class="cx"> ### Establishing a Database Engine {@name=establishing} </span><span class="cx"> </span><span class="cx"> SQLAlchemy 0.2 indicates the source of an Engine strictly via [RFC-1738](http://rfc.net/rfc1738.html) style URLs, combined with optional keyword arguments to specify options for the Engine. The form of the URL is: </span><span class="cx"> </span><del>- {python} - driver://username:password@host:port/database </del><ins>+ $ driver://username:password@host:port/database </ins><span class="cx"> </span><span class="cx"> Available drivernames are `sqlite`, `mysql`, `postgres`, `oracle`, `mssql`, and `firebird`. For sqlite, the database name is the filename to connect to, or the special name ":memory:" which indicates an in-memory database. The URL is typically sent as a string to the `create_engine()` function: </span><span class="cx"> </span><span class="lines">@@ -66,13 +65,13 @@ </span><span class="cx"> * pool_size=5 : the number of connections to keep open inside the connection pool. This is only used with `QueuePool`. </span><span class="cx"> * max_overflow=10 : the number of connections to allow in "overflow", that is connections that can be opened above and beyond the initial five. this is only used with `QueuePool`. </span><span class="cx"> * pool_timeout=30 : number of seconds to wait before giving up on getting a connection from the pool. This is only used with `QueuePool`. </span><del>-* echo=False : if True, the Engine will log all statements as well as a repr() of their parameter lists to the engines logger, which defaults to sys.stdout. A SQLEngine instances' "echo" data member can be modified at any time to turn logging on and off. If set to the string 'debug', result rows will be printed to the standard output as well. -* logger=None : a file-like object where logging output can be sent, if echo is set to True. This defaults to sys.stdout. -* module=None : used by Oracle and Postgres, this is a reference to a DBAPI2 module to be used instead of the engine's default module. For Postgres, the default is psycopg2, or psycopg1 if 2 cannot be found. For Oracle, its cx_Oracle. -* use_ansi=True : used only by Oracle; when False, the Oracle driver attempts to support a particular "quirk" of some Oracle databases, that the LEFT OUTER JOIN SQL syntax is not supported, and the "Oracle join" syntax of using &lt;column1&gt;(+)=&lt;column2&gt; must be used in order to achieve a LEFT OUTER JOIN. Its advised that the Oracle database be configured to have full ANSI support instead of using this feature. -* use_oids=False : used only by Postgres, will enable the column name "oid" as the object ID column. Postgres as of 8.1 has object IDs disabled by default. -* convert_unicode=False : if set to True, all String/character based types will convert Unicode values to raw byte values going into the database, and all raw byte values to Python Unicode coming out in result sets. This is an engine-wide method to provide unicode across the board. For unicode conversion on a column-by-column level, use the Unicode column type instead. -* encoding='utf-8' : the encoding to use for Unicode translations - passed to all encode/decode methods. </del><ins>+* echo=False : if True, the Engine will log all statements as well as a repr() of their parameter lists to the engines logger, which defaults to sys.stdout. The `echo` attribute of `ComposedSQLEngine` can be modified at any time to turn logging on and off. If set to the string `"debug"`, result rows will be printed to the standard output as well. +* logger=None : a file-like object where logging output can be sent, if echo is set to True. Newlines will not be sent with log messages. This defaults to an internal logging object which references `sys.stdout`. +* module=None : used by database implementations which support multiple DBAPI modules, this is a reference to a DBAPI2 module to be used instead of the engine's default module. For Postgres, the default is psycopg2, or psycopg1 if 2 cannot be found. For Oracle, its cx_Oracle. +* use_ansi=True : used only by Oracle; when False, the Oracle driver attempts to support a particular "quirk" of Oracle versions 8 and previous, that the LEFT OUTER JOIN SQL syntax is not supported, and the "Oracle join" syntax of using `&lt;column1&gt;(+)=&lt;column2&gt;` must be used in order to achieve a LEFT OUTER JOIN. +* use_oids=False : used only by Postgres, will enable the column name "oid" as the object ID column, which is also used for the default sort order of tables. Postgres as of 8.1 has object IDs disabled by default. +* convert_unicode=False : if set to True, all String/character based types will convert Unicode values to raw byte values going into the database, and all raw byte values to Python Unicode coming out in result sets. This is an engine-wide method to provide unicode across the board. For unicode conversion on a column-by-column level, use the `Unicode` column type instead. +* encoding='utf-8' : the encoding to use for all Unicode translations, both by engine-wide unicode conversion as well as the `Unicode` type object. </ins><span class="cx"> </span><span class="cx"> ### Using Connections {@name=connections} </span><span class="cx"> </span><span class="lines">@@ -211,7 +210,7 @@ </span><span class="cx"> {python} </span><span class="cx"> # method_a starts a transaction and calls method_b </span><span class="cx"> def method_a(connection): </span><del>- trans = connection.begin() </del><ins>+ trans = connection.begin() # open a transaction </ins><span class="cx"> try: </span><span class="cx"> method_b(connection) </span><span class="cx"> trans.commit() # transaction is committed here </span><span class="lines">@@ -221,7 +220,7 @@ </span><span class="cx"> </span><span class="cx"> # method_b also starts a transaction </span><span class="cx"> def method_b(connection): </span><del>- trans.begin() </del><ins>+ trans = connection.begin() # open a transaction - this runs in the context of method_a's transaction </ins><span class="cx"> try: </span><span class="cx"> connection.execute("insert into mytable values ('bat', 'lala')") </span><span class="cx"> connection.execute(mytable.insert(), col1='bat', col2='lala') </span></span></pre></div> <a id="sqlalchemybranchesschemadocbuildcontentmetadatatxt"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/doc/build/content/metadata.txt (1411 => 1412)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/doc/build/content/metadata.txt 2006-05-06 00:54:41 UTC (rev 1411) +++ sqlalchemy/branches/schema/doc/build/content/metadata.txt 2006-05-06 02:14:06 UTC (rev 1412) </span><span class="lines">@@ -180,27 +180,9 @@ </span><span class="cx"> </span><span class="cx"> ### Creating and Dropping Database Tables {@name=creating} </span><span class="cx"> </span><del>-Creating and dropping individual tables can be done via a `Connection`: </del><ins>+Creating and dropping individual tables can be done via the `create()` and `drop()` methods of `Table`; these methods take an optional `engine` parameter which references an `Engine` or a `Connection`. If not supplied, the `Engine` bound to the `MetaData` will be used, else an error is raised: </ins><span class="cx"> </span><span class="cx"> {python} </span><del>- employees = Table('employees', meta, - Column('employee_id', Integer, primary_key=True), - Column('employee_name', String(60), nullable=False, key='name'), - Column('employee_dept', Integer, ForeignKey("departments.department_id")) - ) - - conn = engine.connect() - {sql}conn.create(employees) - CREATE TABLE employees( - employee_id SERIAL NOT NULL PRIMARY KEY, - employee_name VARCHAR(60) NOT NULL, - employee_dept INTEGER REFERENCES departments(department_id) - ) - {} - -Or off the `create()` method of the `Table` itself; this method takes an optional `engine` parameter which references an `Engine` or a `Connection`. If not supplied, the `Engine` bound to the `MetaData` will be used, else an error is raised: - - {python} </del><span class="cx"> meta = BoundMetaData('sqlite:///:memory:') </span><span class="cx"> employees = Table('employees', meta, </span><span class="cx"> Column('employee_id', Integer, primary_key=True), </span><span class="lines">@@ -215,7 +197,7 @@ </span><span class="cx"> ) </span><span class="cx"> {} </span><span class="cx"> </span><del>-Similarly, both `Connection` and `Table` have a `drop()` method: </del><ins>+`drop()` method: </ins><span class="cx"> </span><span class="cx"> {python} </span><span class="cx"> {sql}employees.drop(engine=e) </span><span class="lines">@@ -335,7 +317,7 @@ </span><span class="cx"> mycolumn datetime default sysdate </span><span class="cx"> ) </span><span class="cx"> </span><del>-PassiveDefaults also send a message to the SQLEngine that data is available after update or insert. The object-relational mapper system uses this information to post-fetch rows after insert or update, so that instances can be refreshed with the new data. Below is a simplified version: </del><ins>+PassiveDefaults also send a message to the `Engine` that data is available after update or insert. The object-relational mapper system uses this information to post-fetch rows after insert or update, so that instances can be refreshed with the new data. Below is a simplified version: </ins><span class="cx"> </span><span class="cx"> {python} </span><span class="cx"> # table with passive defaults </span><span class="lines">@@ -375,7 +357,7 @@ </span><span class="cx"> Column("createdate", DateTime()) </span><span class="cx"> ) </span><span class="cx"> </span><del>-The Sequence is used with Postgres or Oracle to indicate the name of a Sequence that will be used to create default values for a column. When a table with a Sequence on a column is created by SQLAlchemy, the Sequence object is also created. Similarly, the Sequence is dropped when the table is dropped. Sequences are typically used with primary key columns. When using Postgres, if an integer primary key column defines no explicit Sequence or other default method, SQLAlchemy will create the column with the SERIAL keyword, and will pre-execute a sequence named "tablename_columnname_seq" in order to retrieve new primary key values. Oracle, which has no "auto-increment" keyword, requires that a Sequence be created for a table if automatic primary key generation is desired. Note that for all databases, primary key values can always be explicitly stated within the bind parameters for any insert statement as well, removing the need for any kin! d of default generation function. </del><ins>+The Sequence is used with Postgres or Oracle to indicate the name of a database sequence that will be used to create default values for a column. When a table with a Sequence on a column is created in the database by SQLAlchemy, the database sequence object is also created. Similarly, the database sequence is dropped when the table is dropped. Sequences are typically used with primary key columns. When using Postgres, if an integer primary key column defines no explicit Sequence or other default method, SQLAlchemy will create the column with the SERIAL keyword, and will pre-execute a sequence named "tablename_columnname_seq" in order to retrieve new primary key values, if they were not otherwise explicitly stated. Oracle, which has no "auto-increment" keyword, requires that a Sequence be created for a table if automatic primary key generation is desired. </ins><span class="cx"> </span><span class="cx"> A Sequence object can be defined on a Table that is then used for a non-sequence-supporting database. In that case, the Sequence object is simply ignored. Note that a Sequence object is **entirely optional for all databases except Oracle**, as other databases offer options for auto-creating primary key values, such as AUTOINCREMENT, SERIAL, etc. SQLAlchemy will use these default methods for creating primary key values if no Sequence is present on the table metadata. </span><span class="cx"> </span></span></pre></div> <a id="sqlalchemybranchesschemadocbuildcontentsqlconstructiontxt"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/doc/build/content/sqlconstruction.txt (1411 => 1412)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/doc/build/content/sqlconstruction.txt 2006-05-06 00:54:41 UTC (rev 1411) +++ sqlalchemy/branches/schema/doc/build/content/sqlconstruction.txt 2006-05-06 02:14:06 UTC (rev 1412) </span><span class="lines">@@ -1,7 +1,7 @@ </span><span class="cx"> Constructing SQL Queries via Python Expressions {@name=sql} </span><span class="cx"> =============================================== </span><span class="cx"> </span><del>-*Note:* This section describes how to use SQLAlchemy to construct SQL queries and receive result sets. It does *not* cover the object relational mapping capabilities of SQLAlchemy; that is covered later on in [datamapping](rel:datamapping). However, both areas of functionality work similarly in how selection criterion is constructed, so if you are interested just in ORM, you should probably skim through basic [sql_select_whereclause](rel:sql_select_whereclause) construction before moving on. </del><ins>+*Note:* This section describes how to use SQLAlchemy to construct SQL queries and receive result sets. It does *not* cover the object relational mapping capabilities of SQLAlchemy; that is covered later on in [datamapping](rel:datamapping). However, both areas of functionality work similarly in how selection criterion is constructed, so if you are interested just in ORM, you should probably skim through basic [sql_whereclause](rel:sql_whereclause) construction before moving on. </ins><span class="cx"> </span><span class="cx"> Once you have used the `sqlalchemy.schema` module to construct your tables and/or reflect them from the database, performing SQL queries using those table meta data objects is done via the `sqlalchemy.sql` package. This package defines a large set of classes, each of which represents a particular kind of lexical construct within a SQL query; all are descendants of the common base class `sqlalchemy.sql.ClauseElement`. A full query is represented via a structure of `ClauseElement`s. A set of reasonably intuitive creation functions is provided by the `sqlalchemy.sql` package to create these structures; these functions are described in the rest of this section. </span><span class="cx"> </span></span></pre></div> <a id="sqlalchemybranchesschemadocbuildcontentunitofworktxt"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/doc/build/content/unitofwork.txt (1411 => 1412)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/doc/build/content/unitofwork.txt 2006-05-06 00:54:41 UTC (rev 1411) +++ sqlalchemy/branches/schema/doc/build/content/unitofwork.txt 2006-05-06 02:14:06 UTC (rev 1412) </span><span class="lines">@@ -401,20 +401,19 @@ </span><span class="cx"> </span><span class="cx"> The `add()` method will key the `Connection`'s underlying `Engine` to this `SessionTransaction`. When mapper operations are performed against this `Engine`, the `Connection` explicitly added will be used. This **overrides** any other `Connection` objects that the underlying Session was associated with, corresponding to the underlying `Engine` of that `Connection`. However, if the `SessionTransaction` itself is already associated with a `Connection`, then an exception is thrown. </span><span class="cx"> </span><del>-The other way is just to use the `Connection` referenced by the `SessionTransaction`. This is performed via the `connection()` method, and requires passing in a `Mapper` which indicates which underlying `Connection` should be returned. If the `Mapper` argument is `None`, then the `Session` must be globally bound to a specific `Engine` when it was constructed, else the method returns `None`. </del><ins>+The other way is just to use the `Connection` referenced by the `SessionTransaction`. This is performed via the `connection()` method, and requires passing in a class or `Mapper` which indicates which underlying `Connection` should be returned (recall that different `Mappers` may use different underlying `Engines`). If the `class_or_mapper` argument is `None`, then the `Session` must be globally bound to a specific `Engine` when it was constructed, else the method returns `None`. </ins><span class="cx"> </span><span class="cx"> {python title="Get a Connection from the SessionTransaction"} </span><span class="cx"> trans = session.create_transaction() </span><span class="cx"> try: </span><del>- usermapper = session.get_mapper(UserClass) # a convenience method to get a Mapper - connection = trans.connection(usermapper) # get the Connection used by the UserClass' Mapper </del><ins>+ connection = trans.connection(UserClass) # get the Connection used by the UserClass' Mapper </ins><span class="cx"> connection.execute(mytable.update(), {'col1':4, 'col2':17}) </span><span class="cx"> trans.commit() </span><span class="cx"> except: </span><span class="cx"> trans.rollback() </span><span class="cx"> raise </span><span class="cx"> </span><del>-The `connection()` method also exists on the `Session` object itself, and can be called regardless of whether or not a `SessionTransaction` is in progress. If an `Engine` is being used with `threadlocal` strategy, the `Connection` returned will correspond to the connection resources that are bound to the current thread, if any. </del><ins>+The `connection()` method also exists on the `Session` object itself, and can be called regardless of whether or not a `SessionTransaction` is in progress. If a `SessionTransaction` is in progress, it will return the connection referenced by the transaction. If an `Engine` is being used with `threadlocal` strategy, the `Connection` returned will correspond to the connection resources that are bound to the current thread, if any (i.e. it is obtained by calling `contextual_connection()`). </ins><span class="cx"> </span><span class="cx"> #### Using Engine-level Transactions with Sessions </span><span class="cx"> </span></span></pre> </div> </div> </body> </html> |