sqlalchemy-commits Mailing List for SQLAlchemy (Page 376)
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-02-27 01:05:15
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head><style type="text/css"><!-- #msg dl { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; } #msg dt { float: left; width: 6em; font-weight: bold; } #msg dt:after { content:':';} #msg dl, #msg dt, #msg ul, #msg li { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; } #msg dl a { font-weight: bold} #msg dl a:link { color:#fc3; } #msg dl a:active { color:#ff0; } #msg dl a:visited { color:#cc6; } h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; } #msg pre { overflow: auto; background: #ffc; border: 1px #fc0 solid; padding: 6px; } #msg ul, pre { overflow: auto; } #patch { width: 100%; } #patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;} #patch .propset h4, #patch .binary h4 {margin:0;} #patch pre {padding:0;line-height:1.2em;margin:0;} #patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;} #patch .propset .diff, #patch .binary .diff {padding:10px 0;} #patch span {display:block;padding:0 10px;} #patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;} #patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;} #patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;} #patch .lines, .info {color:#888;background:#fff;} --></style> <title>[1057] sqlalchemy/trunk/test: more work on cycles, fleshed out tests for post_update, fix to the delete phase of a one-to-many post update</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1057</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-02-26 19:05:01 -0600 (Sun, 26 Feb 2006)</dd> </dl> <h3>Log Message</h3> <pre>more work on cycles, fleshed out tests for post_update, fix to the delete phase of a one-to-many post update closes [ticket:67]</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunklibsqlalchemymappingpropertiespy">sqlalchemy/trunk/lib/sqlalchemy/mapping/properties.py</a></li> <li><a href="#sqlalchemytrunktestcyclespy">sqlalchemy/trunk/test/cycles.py</a></li> <li><a href="#sqlalchemytrunktesttestbasepy">sqlalchemy/trunk/test/testbase.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunklibsqlalchemymappingpropertiespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/mapping/properties.py (1056 => 1057)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/mapping/properties.py 2006-02-26 23:40:15 UTC (rev 1056) +++ sqlalchemy/trunk/lib/sqlalchemy/mapping/properties.py 2006-02-27 01:05:01 UTC (rev 1057) </span><span class="lines">@@ -458,7 +458,7 @@ </span><span class="cx"> elif self.direction == PropertyLoader.ONETOMANY and delete: </span><span class="cx"> # head object is being deleted, and we manage its list of child objects </span><span class="cx"> # the child objects have to have their foreign key to the parent set to NULL </span><del>- if self.private: </del><ins>+ if self.private and not self.post_update: </ins><span class="cx"> # if we are privately managed, then all our objects should </span><span class="cx"> # have been marked as "todelete" already and no attribute adjustment is needed </span><span class="cx"> return </span></span></pre></div> <a id="sqlalchemytrunktestcyclespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/test/cycles.py (1056 => 1057)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/test/cycles.py 2006-02-26 23:40:15 UTC (rev 1056) +++ sqlalchemy/trunk/test/cycles.py 2006-02-27 01:05:01 UTC (rev 1057) </span><span class="lines">@@ -19,7 +19,7 @@ </span><span class="cx"> def __repr__(self): </span><span class="cx"> return "%s(%s)" % (self.__class__.__name__, repr(self.data)) </span><span class="cx"> </span><del>-class SelfCycleTest(AssertMixin): </del><ins>+class SelfReferentialTest(AssertMixin): </ins><span class="cx"> """tests a self-referential mapper, with an additional list of child objects.""" </span><span class="cx"> def setUpAll(self): </span><span class="cx"> testbase.db.tables.clear() </span><span class="lines">@@ -67,8 +67,8 @@ </span><span class="cx"> objectstore.delete(a) </span><span class="cx"> objectstore.commit() </span><span class="cx"> </span><del>-class CycleTest(AssertMixin): - """tests two mappers with a bi-directional dependency""" </del><ins>+class BiDirectionalOneToManyTest(AssertMixin): + """tests two mappers with a one-to-many relation to each other.""" </ins><span class="cx"> def setUpAll(self): </span><span class="cx"> testbase.db.tables.clear() </span><span class="cx"> global t1 </span><span class="lines">@@ -112,8 +112,8 @@ </span><span class="cx"> b.c1s.append(c) </span><span class="cx"> objectstore.commit() </span><span class="cx"> </span><del>-class CycleWDepsTest(AssertMixin): - """tests two mappers with a bi-directional dependency, and child objects on one of them""" </del><ins>+class BiDirectionalOneToManyTest2(AssertMixin): + """tests two mappers with a one-to-many relation to each other, with a second one-to-many on one of the mappers""" </ins><span class="cx"> def setUpAll(self): </span><span class="cx"> testbase.db.tables.clear() </span><span class="cx"> global t1 </span><span class="lines">@@ -178,25 +178,35 @@ </span><span class="cx"> objectstore.delete(c) </span><span class="cx"> objectstore.commit() </span><span class="cx"> </span><del>-class CycleTest2(AssertMixin): </del><ins>+class OneToManyManyToOneTest(AssertMixin): + """tests two mappers, one has a one-to-many on the other mapper, the other has a separate many-to-one relationship to the first. + two tests will have a row for each item that is dependent on the other. without the "post_update" flag, such relationships + raise an exception when dependencies are sorted.""" </ins><span class="cx"> def setUpAll(self): </span><span class="cx"> testbase.db.tables.clear() </span><span class="cx"> global person </span><span class="cx"> global ball </span><ins>+ ball = Table('ball', db, + Column('id', Integer, Sequence('ball_id_seq', optional=True), primary_key=True), + Column('person_id', Integer), + ) </ins><span class="cx"> person = Table('person', db, </span><span class="cx"> Column('id', Integer, Sequence('person_id_seq', optional=True), primary_key=True), </span><span class="cx"> Column('favoriteBall_id', Integer, ForeignKey('ball.id')), </span><ins>+# Column('favoriteBall_id', Integer), </ins><span class="cx"> ) </span><del>- ball = Table('ball', db, - Column('id', Integer, Sequence('ball_id_seq', optional=True), primary_key=True), - Column('person_id', Integer), - ) </del><span class="cx"> </span><span class="cx"> ball.create() </span><span class="cx"> person.create() </span><ins>+# person.c.favoriteBall_id.append_item(ForeignKey('ball.id')) </ins><span class="cx"> ball.c.person_id.append_item(ForeignKey('person.id')) </span><span class="cx"> </span><ins>+ # make the test more complete for postgres + if db.engine.__module__.endswith('postgres'): + db.execute("alter table ball add constraint fk_ball_person foreign key (person_id) references person(id)", {}) </ins><span class="cx"> def tearDownAll(self): </span><ins>+ if db.engine.__module__.endswith('postgres'): + db.execute("alter table ball drop constraint fk_ball_person", {}) </ins><span class="cx"> person.drop() </span><span class="cx"> ball.drop() </span><span class="cx"> </span><span class="lines">@@ -228,8 +238,8 @@ </span><span class="cx"> p.balls.append(b) </span><span class="cx"> objectstore.commit() </span><span class="cx"> </span><del>- def testrowcycle(self): - """tests a cycle between two rows""" </del><ins>+ def testpostupdate_m2o(self): + """tests a cycle between two rows, with a post_update on the many-to-one""" </ins><span class="cx"> class Person(object): </span><span class="cx"> pass </span><span class="cx"> </span><span class="lines">@@ -252,12 +262,217 @@ </span><span class="cx"> p.balls.append(Ball()) </span><span class="cx"> p.balls.append(Ball()) </span><span class="cx"> p.favorateBall = b </span><del>- objectstore.commit() - </del><ins>+ + self.assert_sql(db, lambda: objectstore.uow().commit(), [ + ( + "INSERT INTO person (favoriteBall_id) VALUES (:favoriteBall_id)", + {'favoriteBall_id': None} + ), + ( + "INSERT INTO ball (person_id) VALUES (:person_id)", + lambda:{'person_id':p.id} + ), + ( + "INSERT INTO ball (person_id) VALUES (:person_id)", + lambda:{'person_id':p.id} + ), + ( + "INSERT INTO ball (person_id) VALUES (:person_id)", + lambda:{'person_id':p.id} + ), + ( + "INSERT INTO ball (person_id) VALUES (:person_id)", + lambda:{'person_id':p.id} + ), + ( + "UPDATE person SET favoriteBall_id=:favoriteBall_id WHERE person.id = :person_id", + lambda:[{'favoriteBall_id':p.favorateBall.id,'person_id':p.id}] + ) + ], + with_sequences= [ + ( + "INSERT INTO person (id, favoriteBall_id) VALUES (:id, :favoriteBall_id)", + lambda:{'id':db.last_inserted_ids()[0], 'favoriteBall_id': None} + ), + ( + "INSERT INTO ball (id, person_id) VALUES (:id, :person_id)", + lambda:{'id':db.last_inserted_ids()[0],'person_id':p.id} + ), + ( + "INSERT INTO ball (id, person_id) VALUES (:id, :person_id)", + lambda:{'id':db.last_inserted_ids()[0],'person_id':p.id} + ), + ( + "INSERT INTO ball (id, person_id) VALUES (:id, :person_id)", + lambda:{'id':db.last_inserted_ids()[0],'person_id':p.id} + ), + ( + "INSERT INTO ball (id, person_id) VALUES (:id, :person_id)", + lambda:{'id':db.last_inserted_ids()[0],'person_id':p.id} + ), + # heres the post update + ( + "UPDATE person SET favoriteBall_id=:favoriteBall_id WHERE person.id = :person_id", + lambda:[{'favoriteBall_id':p.favorateBall.id,'person_id':p.id}] + ) + ]) </ins><span class="cx"> objectstore.delete(p) </span><del>- objectstore.commit() </del><ins>+ self.assert_sql(db, lambda: objectstore.uow().commit(), [ + # heres the post update (which is a pre-update with deletes) + ( + "UPDATE person SET favoriteBall_id=:favoriteBall_id WHERE person.id = :person_id", + lambda:[{'person_id': p.id, 'favoriteBall_id': None}] + ), + ( + "DELETE FROM ball WHERE ball.id = :id", + None + # order cant be predicted, but something like: + #lambda:[{'id': 1L}, {'id': 4L}, {'id': 3L}, {'id': 2L}] + ), + ( + "DELETE FROM person WHERE person.id = :id", + lambda:[{'id': p.id}] + ) </ins><span class="cx"> </span><ins>+ + ]) </ins><span class="cx"> </span><ins>+ def testpostupdate_o2m(self): + """tests a cycle between two rows, with a post_update on the one-to-many""" + class Person(object): + pass + + class Ball(object): + pass + + Ball.mapper = mapper(Ball, ball) + Person.mapper = mapper(Person, person, properties= dict( + balls = relation(Ball.mapper, primaryjoin=ball.c.person_id==person.c.id, foreignkey=ball.c.person_id, private=True, post_update=True), + favorateBall = relation(Ball.mapper, primaryjoin=person.c.favoriteBall_id==ball.c.id, foreignkey=person.c.favoriteBall_id), + ) + ) + + print str(Person.mapper.props['balls'].primaryjoin) + + b = Ball() + p = Person() + p.balls.append(b) + b2 = Ball() + p.balls.append(b2) + b3 = Ball() + p.balls.append(b3) + b4 = Ball() + p.balls.append(b4) + p.favorateBall = b +# objectstore.commit() + self.assert_sql(db, lambda: objectstore.uow().commit(), [ + ( + "INSERT INTO ball (person_id) VALUES (:person_id)", + {'person_id':None} + ), + ( + "INSERT INTO ball (person_id) VALUES (:person_id)", + {'person_id':None} + ), + ( + "INSERT INTO ball (person_id) VALUES (:person_id)", + {'person_id':None} + ), + ( + "INSERT INTO ball (person_id) VALUES (:person_id)", + {'person_id':None} + ), + ( + "INSERT INTO person (favoriteBall_id) VALUES (:favoriteBall_id)", + lambda:{'favoriteBall_id':b.id} + ), + # heres the post update on each one-to-many item + ( + "UPDATE ball SET person_id=:person_id WHERE ball.id = :ball_id", + lambda:[{'person_id':p.id,'ball_id':b.id}] + ), + ( + "UPDATE ball SET person_id=:person_id WHERE ball.id = :ball_id", + lambda:[{'person_id':p.id,'ball_id':b2.id}] + ), + ( + "UPDATE ball SET person_id=:person_id WHERE ball.id = :ball_id", + lambda:[{'person_id':p.id,'ball_id':b3.id}] + ), + ( + "UPDATE ball SET person_id=:person_id WHERE ball.id = :ball_id", + lambda:[{'person_id':p.id,'ball_id':b4.id}] + ), + ], + with_sequences=[ + ( + "INSERT INTO ball (id, person_id) VALUES (:id, :person_id)", + lambda:{'id':db.last_inserted_ids()[0], 'person_id':None} + ), + ( + "INSERT INTO ball (id, person_id) VALUES (:id, :person_id)", + lambda:{'id':db.last_inserted_ids()[0], 'person_id':None} + ), + ( + "INSERT INTO ball (id, person_id) VALUES (:id, :person_id)", + lambda:{'id':db.last_inserted_ids()[0], 'person_id':None} + ), + ( + "INSERT INTO ball (id, person_id) VALUES (:id, :person_id)", + lambda:{'id':db.last_inserted_ids()[0], 'person_id':None} + ), + ( + "INSERT INTO person (id, favoriteBall_id) VALUES (:id, :favoriteBall_id)", + lambda:{'id':db.last_inserted_ids()[0], 'favoriteBall_id':b.id} + ), + ( + "UPDATE ball SET person_id=:person_id WHERE ball.id = :ball_id", + lambda:[{'person_id':p.id,'ball_id':b.id}] + ), + ( + "UPDATE ball SET person_id=:person_id WHERE ball.id = :ball_id", + lambda:[{'person_id':p.id,'ball_id':b2.id}] + ), + ( + "UPDATE ball SET person_id=:person_id WHERE ball.id = :ball_id", + lambda:[{'person_id':p.id,'ball_id':b3.id}] + ), + ( + "UPDATE ball SET person_id=:person_id WHERE ball.id = :ball_id", + lambda:[{'person_id':p.id,'ball_id':b4.id}] + ), + ]) + + objectstore.delete(p) + self.assert_sql(db, lambda: objectstore.uow().commit(), [ + ( + "UPDATE ball SET person_id=:person_id WHERE ball.id = :ball_id", + lambda:[{'person_id': None, 'ball_id': b.id}] + ), + ( + "UPDATE ball SET person_id=:person_id WHERE ball.id = :ball_id", + lambda:[{'person_id': None, 'ball_id': b2.id}] + ), + ( + "UPDATE ball SET person_id=:person_id WHERE ball.id = :ball_id", + lambda:[{'person_id': None, 'ball_id': b3.id}] + ), + ( + "UPDATE ball SET person_id=:person_id WHERE ball.id = :ball_id", + lambda:[{'person_id': None, 'ball_id': b4.id}] + ), + ( + "DELETE FROM person WHERE person.id = :id", + lambda:[{'id':p.id}] + ), + ( + "DELETE FROM ball WHERE ball.id = :id", + None + # the order of deletion is not predictable, but its roughly: + # lambda:[{'id': b.id}, {'id': b2.id}, {'id': b3.id}, {'id': b4.id}] + ) + ]) + </ins><span class="cx"> if __name__ == "__main__": </span><span class="cx"> testbase.main() </span><span class="cx"> </span></span></pre></div> <a id="sqlalchemytrunktesttestbasepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/test/testbase.py (1056 => 1057)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/test/testbase.py 2006-02-26 23:40:15 UTC (rev 1056) +++ sqlalchemy/trunk/test/testbase.py 2006-02-27 01:05:01 UTC (rev 1057) </span><span class="lines">@@ -143,7 +143,7 @@ </span><span class="cx"> </span><span class="cx"> query = self.convert_statement(query) </span><span class="cx"> </span><del>- self.unittest.assert_(statement == query and params == parameters, "Testing for query '%s' params %s, received '%s' with params %s" % (query, repr(params), statement, repr(parameters))) </del><ins>+ self.unittest.assert_(statement == query and (params is None or params == parameters), "Testing for query '%s' params %s, received '%s' with params %s" % (query, repr(params), statement, repr(parameters))) </ins><span class="cx"> self.sql_count += 1 </span><span class="cx"> return self.realexec(proxy, compiled, parameters, **kwargs) </span><span class="cx"> </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-02-26 23:40: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>[1056] sqlalchemy/trunk/lib/sqlalchemy/mapping/__init__.py: imported casacde_mappers</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1056</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-02-26 17:40:15 -0600 (Sun, 26 Feb 2006)</dd> </dl> <h3>Log Message</h3> <pre>imported casacde_mappers</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunklibsqlalchemymapping__init__py">sqlalchemy/trunk/lib/sqlalchemy/mapping/__init__.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunklibsqlalchemymapping__init__py"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/mapping/__init__.py (1055 => 1056)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/mapping/__init__.py 2006-02-26 22:57:46 UTC (rev 1055) +++ sqlalchemy/trunk/lib/sqlalchemy/mapping/__init__.py 2006-02-26 23:40:15 UTC (rev 1056) </span><span class="lines">@@ -21,7 +21,7 @@ </span><span class="cx"> </span><span class="cx"> __all__ = ['relation', 'eagerload', 'lazyload', 'noload', 'deferred', 'defer', 'undefer', </span><span class="cx"> 'mapper', 'clear_mappers', 'objectstore', 'sql', 'extension', 'class_mapper', 'object_mapper', 'MapperExtension', </span><del>- 'assign_mapper' </del><ins>+ 'assign_mapper', 'cascade_mappers' </ins><span class="cx"> ] </span><span class="cx"> </span><span class="cx"> def relation(*args, **kwargs): </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-02-26 22:58: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>[1055] sqlalchemy/trunk/test: Merge indexes [1047]:[1048] into trunk (for #6)</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1055</dd> <dt>Author</dt> <dd>jpellerin</dd> <dt>Date</dt> <dd>2006-02-26 16:57:46 -0600 (Sun, 26 Feb 2006)</dd> </dl> <h3>Log Message</h3> <pre>Merge indexes [1047]:[1048] into trunk (for #6)</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunklibsqlalchemyansisqlpy">sqlalchemy/trunk/lib/sqlalchemy/ansisql.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemydatabasessqlitepy">sqlalchemy/trunk/lib/sqlalchemy/databases/sqlite.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemyschemapy">sqlalchemy/trunk/lib/sqlalchemy/schema.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemysqlpy">sqlalchemy/trunk/lib/sqlalchemy/sql.py</a></li> <li><a href="#sqlalchemytrunktestindexespy">sqlalchemy/trunk/test/indexes.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunklibsqlalchemyansisqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/ansisql.py (1054 => 1055)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/ansisql.py 2006-02-26 22:23:01 UTC (rev 1054) +++ sqlalchemy/trunk/lib/sqlalchemy/ansisql.py 2006-02-26 22:57:46 UTC (rev 1055) </span><span class="lines">@@ -517,8 +517,11 @@ </span><span class="cx"> self.append("\tPRIMARY KEY (%s)" % string.join([c.name for c in pks],', ')) </span><span class="cx"> </span><span class="cx"> self.append("\n)%s\n\n" % self.post_create_table(table)) </span><del>- self.execute() - </del><ins>+ self.execute() + if hasattr(table, 'indexes'): + for index in table.indexes: + self.visit_index(index) + </ins><span class="cx"> def post_create_table(self, table): </span><span class="cx"> return '' </span><span class="cx"> </span><span class="lines">@@ -550,6 +553,8 @@ </span><span class="cx"> self.execute() </span><span class="cx"> </span><span class="cx"> def visit_table(self, table): </span><ins>+ # NOTE: indexes on the table will be automatically dropped, so + # no need to drop them individually </ins><span class="cx"> self.append("\nDROP TABLE " + table.fullname) </span><span class="cx"> self.execute() </span><span class="cx"> </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemydatabasessqlitepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/databases/sqlite.py (1054 => 1055)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/databases/sqlite.py 2006-02-26 22:23:01 UTC (rev 1054) +++ sqlalchemy/trunk/lib/sqlalchemy/databases/sqlite.py 2006-02-26 22:57:46 UTC (rev 1055) </span><span class="lines">@@ -260,6 +260,9 @@ </span><span class="cx"> self.append("\tUNIQUE (%s)" % string.join([c.name for c in table.primary_key],', ')) </span><span class="cx"> </span><span class="cx"> self.append("\n)\n\n") </span><del>- self.execute() </del><ins>+ self.execute() + if hasattr(table, 'indexes'): + for index in table.indexes: + self.visit_index(index) </ins><span class="cx"> </span><span class="cx"> </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemyschemapy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/schema.py (1054 => 1055)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/schema.py 2006-02-26 22:23:01 UTC (rev 1054) +++ sqlalchemy/trunk/lib/sqlalchemy/schema.py 2006-02-26 22:57:46 UTC (rev 1055) </span><span class="lines">@@ -160,7 +160,10 @@ </span><span class="cx"> self.primary_key.append(column) </span><span class="cx"> column.table = self </span><span class="cx"> column.type = self.engine.type_descriptor(column.type) </span><del>- </del><ins>+ + def append_index(self, index): + self.indexes[index.name] = index + </ins><span class="cx"> def _set_parent(self, schema): </span><span class="cx"> schema.tables[self.name] = self </span><span class="cx"> self.schema = schema </span><span class="lines">@@ -170,6 +173,32 @@ </span><span class="cx"> for c in self.columns: </span><span class="cx"> c.accept_schema_visitor(visitor) </span><span class="cx"> return visitor.visit_table(self) </span><ins>+ + def append_index_column(self, column, index=None, unique=None): + """Add an index or a column to an existing index of the same name. + """ + if index is not None and unique is not None: + raise ValueError("index and unique may not both be specified") + if index: + if index is True: + name = 'ix_%s' % column.name + else: + name = index + elif unique: + if unique is True: + name = 'ux_%s' % column.name + else: + name = unique + # find this index in self.indexes + # add this column to it if found + # otherwise create new + try: + index = self.indexes[name] + index.append_column(column) + except KeyError: + index = Index(name, column, unique=unique) + return index + </ins><span class="cx"> def deregister(self): </span><span class="cx"> """removes this table from it's engines table registry. this does not </span><span class="cx"> issue a SQL DROP statement.""" </span><span class="lines">@@ -224,9 +253,22 @@ </span><span class="cx"> which will be invoked upon insert if this column is not present in the insert list or is given a value </span><span class="cx"> of None. </span><span class="cx"> </span><del>- hidden=False : indicates this column should not be listed in the table's list of columns. Used for the "oid" - column, which generally isnt in column lists. - """ </del><ins>+ hidden=False : indicates this column should not be listed in the + table's list of columns. Used for the "oid" column, which generally + isnt in column lists. + + index=None : True or index name. Indicates that this column is + indexed. Pass true to autogenerate the index name. Pass a string to + specify the index name. Multiple columns that specify the same index + name will all be included in the index, in the order of their + creation. + + unique=None : True or undex name. Indicates that this column is + indexed in a unique index . Pass true to autogenerate the index + name. Pass a string to specify the index name. Multiple columns that + specify the same index name will all be included in the index, in the + order of their creation. """ + </ins><span class="cx"> name = str(name) # in case of incoming unicode </span><span class="cx"> super(Column, self).__init__(name, None, type) </span><span class="cx"> self.args = args </span><span class="lines">@@ -235,6 +277,10 @@ </span><span class="cx"> self.nullable = kwargs.pop('nullable', not self.primary_key) </span><span class="cx"> self.hidden = kwargs.pop('hidden', False) </span><span class="cx"> self.default = kwargs.pop('default', None) </span><ins>+ self.index = kwargs.pop('index', None) + self.unique = kwargs.pop('unique', None) + if self.index is not None and self.unique is not None: + raise ArgumentError("Column may not define both index and unique") </ins><span class="cx"> self._foreign_key = None </span><span class="cx"> self._orig = None </span><span class="cx"> self._parent = None </span><span class="lines">@@ -269,6 +315,10 @@ </span><span class="cx"> if getattr(self, 'table', None) is not None: </span><span class="cx"> raise ArgumentError("this Column already has a table!") </span><span class="cx"> table.append_column(self) </span><ins>+ if self.index or self.unique: + table.append_index_column(self, index=self.index, + unique=self.unique) + </ins><span class="cx"> if self.default is not None: </span><span class="cx"> self.default = ColumnDefault(self.default) </span><span class="cx"> self._init_items(self.default) </span><span class="lines">@@ -429,7 +479,6 @@ </span><span class="cx"> class Index(SchemaItem): </span><span class="cx"> """Represents an index of columns from a database table </span><span class="cx"> """ </span><del>- </del><span class="cx"> def __init__(self, name, *columns, **kw): </span><span class="cx"> """Constructs an index object. Arguments are: </span><span class="cx"> </span><span class="lines">@@ -443,24 +492,34 @@ </span><span class="cx"> unique=True : create a unique index </span><span class="cx"> """ </span><span class="cx"> self.name = name </span><del>- self.columns = columns </del><ins>+ self.columns = [] + self.table = None </ins><span class="cx"> self.unique = kw.pop('unique', False) </span><del>- self._init_items() </del><ins>+ self._init_items(*columns) </ins><span class="cx"> </span><span class="cx"> engine = property(lambda s:s.table.engine) </span><del>- def _init_items(self): </del><ins>+ def _init_items(self, *args): + for column in args: + self.append_column(column) + + def append_column(self, column): </ins><span class="cx"> # make sure all columns are from the same table </span><del>- # FIXME: and no column is repeated - self.table = None - for column in self.columns: - if self.table is None: - self.table = column.table - elif column.table != self.table: - # all columns muse be from same table - raise ArgumentError("All index columns must be from same table. " - "%s is from %s not %s" % (column, - column.table, - self.table)) </del><ins>+ # and no column is repeated + if self.table is None: + self.table = column.table + self.table.append_index(self) + elif column.table != self.table: + # all columns muse be from same table + raise ArgumentError("All index columns must be from same table. " + "%s is from %s not %s" % (column, + column.table, + self.table)) + elif column.name in [ c.name for c in self.columns ]: + raise ArgumentError("A column may not appear twice in the " + "same index (%s already has column %s)" + % (self.name, column)) + self.columns.append(column) + </ins><span class="cx"> def create(self): </span><span class="cx"> self.engine.create(self) </span><span class="cx"> return self </span><span class="lines">@@ -501,7 +560,7 @@ </span><span class="cx"> """visit a ForeignKey.""" </span><span class="cx"> pass </span><span class="cx"> def visit_index(self, index): </span><del>- """visit an Index (not implemented yet).""" </del><ins>+ """visit an Index.""" </ins><span class="cx"> pass </span><span class="cx"> def visit_passive_default(self, default): </span><span class="cx"> """visit a passive default""" </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemysqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/sql.py (1054 => 1055)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/sql.py 2006-02-26 22:23:01 UTC (rev 1054) +++ sqlalchemy/trunk/lib/sqlalchemy/sql.py 2006-02-26 22:57:46 UTC (rev 1055) </span><span class="lines">@@ -982,11 +982,14 @@ </span><span class="cx"> super(TableClause, self).__init__(name) </span><span class="cx"> self.name = self.id = self.fullname = name </span><span class="cx"> self._columns = util.OrderedProperties() </span><ins>+ self._indexes = util.OrderedProperties() </ins><span class="cx"> self._foreign_keys = [] </span><span class="cx"> self._primary_key = [] </span><span class="cx"> for c in columns: </span><span class="cx"> self.append_column(c) </span><span class="cx"> </span><ins>+ indexes = property(lambda s:s._indexes) + </ins><span class="cx"> def append_column(self, c): </span><span class="cx"> self._columns[c.text] = c </span><span class="cx"> c.table = self </span></span></pre></div> <a id="sqlalchemytrunktestindexespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/test/indexes.py (1054 => 1055)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/test/indexes.py 2006-02-26 22:23:01 UTC (rev 1054) +++ sqlalchemy/trunk/test/indexes.py 2006-02-26 22:57:46 UTC (rev 1055) </span><span class="lines">@@ -6,8 +6,12 @@ </span><span class="cx"> </span><span class="cx"> def setUp(self): </span><span class="cx"> self.created = [] </span><del>- </del><ins>+ self.echo = testbase.db.echo + self.logger = testbase.db.logger + </ins><span class="cx"> def tearDown(self): </span><ins>+ testbase.db.echo = self.echo + testbase.db.logger = testbase.db.engine.logger = self.logger </ins><span class="cx"> if self.created: </span><span class="cx"> self.created.reverse() </span><span class="cx"> for entity in self.created: </span><span class="lines">@@ -26,11 +30,87 @@ </span><span class="cx"> employees.c.last_name, employees.c.first_name) </span><span class="cx"> i.create() </span><span class="cx"> self.created.append(i) </span><ins>+ assert employees.indexes['employee_name_index'] is i </ins><span class="cx"> </span><del>- i = Index('employee_email_index', - employees.c.email_address, unique=True) </del><ins>+ i2 = Index('employee_email_index', + employees.c.email_address, unique=True) + i2.create() + self.created.append(i2) + assert employees.indexes['employee_email_index'] is i2 + + def test_index_create_camelcase(self): + """test that mixed-case index identifiers are legal""" + employees = Table('companyEmployees', testbase.db, + Column('id', Integer, primary_key=True), + Column('firstName', String), + Column('lastName', String), + Column('emailAddress', String)) + employees.create() + self.created.append(employees) + + i = Index('employeeNameIndex', + employees.c.lastName, employees.c.firstName) </ins><span class="cx"> i.create() </span><span class="cx"> self.created.append(i) </span><span class="cx"> </span><ins>+ i = Index('employeeEmailIndex', + employees.c.emailAddress, unique=True) + i.create() + self.created.append(i) + + # Check that the table is useable. This is mostly for pg, + # which can be somewhat sticky with mixed-case identifiers + employees.insert().execute(firstName='Joe', lastName='Smith') + ss = employees.select().execute().fetchall() + assert ss[0].firstName == 'Joe' + assert ss[0].lastName == 'Smith' + + def test_index_create_inline(self): + """Test indexes defined with tables""" + + testbase.db.echo = True + capt = [] + class dummy: + pass + stream = dummy() + stream.write = capt.append + testbase.db.logger = testbase.db.engine.logger = stream + + events = Table('events', testbase.db, + Column('id', Integer, primary_key=True), + Column('name', String(30), unique=True), + Column('location', String(30), index=True), + Column('sport', String(30), + unique='sport_announcer'), + Column('announcer', String(30), + unique='sport_announcer'), + Column('winner', String(30), index='idx_winners')) + + index_names = [ ix.name for ix in events.indexes ] + assert 'ux_name' in index_names + assert 'ix_location' in index_names + assert 'sport_announcer' in index_names + assert 'idx_winners' in index_names + assert len(index_names) == 4 + + events.create() + self.created.append(events) + + # verify that the table is functional + events.insert().execute(id=1, name='hockey finals', location='rink', + sport='hockey', announcer='some canadian', + winner='sweden') + ss = events.select().execute().fetchall() + + assert capt[0].strip().startswith('CREATE TABLE events') + assert capt[2].strip() == \ + 'CREATE UNIQUE INDEX ux_name ON events (name)' + assert capt[4].strip() == \ + 'CREATE INDEX ix_location ON events (location)' + assert capt[6].strip() == \ + 'CREATE UNIQUE INDEX sport_announcer ON events (sport, announcer)' + assert capt[8].strip() == \ + 'CREATE INDEX idx_winners ON events (winner)' + </ins><span class="cx"> if __name__ == "__main__": </span><span class="cx"> testbase.main() </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-02-26 22:23: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>[1054] sqlalchemy/trunk/test: implemented SyncRules for mapper with inheritance relationship, fixes [ticket:81]</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1054</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-02-26 16:23:01 -0600 (Sun, 26 Feb 2006)</dd> </dl> <h3>Log Message</h3> <pre>implemented SyncRules for mapper with inheritance relationship, fixes [ticket:81] TableFinder becomes a list-implementing object (should probably create clauseutils or sqlutils for these little helper visitors)</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunklibsqlalchemymappingmapperpy">sqlalchemy/trunk/lib/sqlalchemy/mapping/mapper.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemymappingpropertiespy">sqlalchemy/trunk/lib/sqlalchemy/mapping/properties.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemymappingsyncpy">sqlalchemy/trunk/lib/sqlalchemy/mapping/sync.py</a></li> <li><a href="#sqlalchemytrunktestinheritancepy">sqlalchemy/trunk/test/inheritance.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunklibsqlalchemymappingmapperpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/mapping/mapper.py (1053 => 1054)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/mapping/mapper.py 2006-02-26 21:45:10 UTC (rev 1053) +++ sqlalchemy/trunk/lib/sqlalchemy/mapping/mapper.py 2006-02-26 22:23:01 UTC (rev 1054) </span><span class="lines">@@ -9,6 +9,7 @@ </span><span class="cx"> import sqlalchemy.schema as schema </span><span class="cx"> import sqlalchemy.engine as engine </span><span class="cx"> import sqlalchemy.util as util </span><ins>+import sync </ins><span class="cx"> from sqlalchemy.exceptions import * </span><span class="cx"> import objectstore </span><span class="cx"> import sys </span><span class="lines">@@ -64,14 +65,15 @@ </span><span class="cx"> self.primarytable = inherits.primarytable </span><span class="cx"> # inherit_condition is optional since the join can figure it out </span><span class="cx"> self.table = sql.join(inherits.table, table, inherit_condition) </span><ins>+ self._synchronizer = sync.ClauseSynchronizer(self, self, sync.ONETOMANY) + self._synchronizer.compile(self.table.onclause, inherits.tables, TableFinder(table)) </ins><span class="cx"> else: </span><span class="cx"> self.primarytable = self.table </span><del>- </del><ins>+ self._synchronizer = None + </ins><span class="cx"> # locate all tables contained within the "table" passed in, which </span><span class="cx"> # may be a join or other construct </span><del>- tf = TableFinder() - self.table.accept_visitor(tf) - self.tables = tf.tables </del><ins>+ self.tables = TableFinder(self.table) </ins><span class="cx"> </span><span class="cx"> # determine primary key columns, either passed in, or get them from our set of tables </span><span class="cx"> self.pks_by_table = {} </span><span class="lines">@@ -170,7 +172,6 @@ </span><span class="cx"> self.props[key] = prop.copy() </span><span class="cx"> self.props[key].parent = self </span><span class="cx"> self.props[key].key = None # force re-init </span><del>- </del><span class="cx"> l = [(key, prop) for key, prop in self.props.iteritems()] </span><span class="cx"> for key, prop in l: </span><span class="cx"> if getattr(prop, 'key', None) is None: </span><span class="lines">@@ -589,6 +590,8 @@ </span><span class="cx"> for c in table.c: </span><span class="cx"> if self._getattrbycolumn(obj, c) is None: </span><span class="cx"> self._setattrbycolumn(obj, c, row[c]) </span><ins>+ if self._synchronizer is not None: + self._synchronizer.execute(obj, obj) </ins><span class="cx"> self.extension.after_insert(self, obj) </span><span class="cx"> </span><span class="cx"> def delete_obj(self, objects, uow): </span><span class="lines">@@ -878,11 +881,20 @@ </span><span class="cx"> </span><span class="cx"> class TableFinder(sql.ClauseVisitor): </span><span class="cx"> """given a Clause, locates all the Tables within it into a list.""" </span><del>- def __init__(self): </del><ins>+ def __init__(self, table): </ins><span class="cx"> self.tables = [] </span><ins>+ table.accept_visitor(self) </ins><span class="cx"> def visit_table(self, table): </span><span class="cx"> self.tables.append(table) </span><del>- </del><ins>+ def __getitem__(self, i): + return self.tables[i] + def __iter__(self): + return iter(self.tables) + def __contains__(self, obj): + return obj in self.tables + def __add__(self, obj): + return self.tables + obj + </ins><span class="cx"> def hash_key(obj): </span><span class="cx"> if obj is None: </span><span class="cx"> return 'None' </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemymappingpropertiespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/mapping/properties.py (1053 => 1054)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/mapping/properties.py 2006-02-26 21:45:10 UTC (rev 1053) +++ sqlalchemy/trunk/lib/sqlalchemy/mapping/properties.py 2006-02-26 22:23:01 UTC (rev 1054) </span><span class="lines">@@ -49,7 +49,9 @@ </span><span class="cx"> def execute(self, instance, row, identitykey, imap, isnew): </span><span class="cx"> if isnew: </span><span class="cx"> instance.__dict__[self.key] = row[self.columns[0]] </span><del>- </del><ins>+ def __repr__(self): + return "ColumnProperty(%s)" % repr([str(c) for c in self.columns]) + </ins><span class="cx"> class DeferredColumnProperty(ColumnProperty): </span><span class="cx"> """describes an object attribute that corresponds to a table column, which also </span><span class="cx"> will "lazy load" its value from the table. this is per-column lazy loading.""" </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemymappingsyncpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/mapping/sync.py (1053 => 1054)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/mapping/sync.py 2006-02-26 21:45:10 UTC (rev 1053) +++ sqlalchemy/trunk/lib/sqlalchemy/mapping/sync.py 2006-02-26 22:23:01 UTC (rev 1054) </span><span class="lines">@@ -1,7 +1,6 @@ </span><span class="cx"> import sqlalchemy.sql as sql </span><span class="cx"> import sqlalchemy.schema as schema </span><span class="cx"> from sqlalchemy.exceptions import * </span><del>-import properties </del><span class="cx"> </span><span class="cx"> """contains the ClauseSynchronizer class which is used to map attributes between two objects </span><span class="cx"> in a manner corresponding to a SQL clause that compares column values.""" </span><span class="lines">@@ -74,7 +73,7 @@ </span><span class="cx"> if len(self.syncrules) == rules_added: </span><span class="cx"> raise ArgumentError("No syncrules generated for join criterion " + str(sqlclause)) </span><span class="cx"> </span><del>- def execute(self, source, dest, obj, child, clearkeys): </del><ins>+ def execute(self, source, dest, obj=None, child=None, clearkeys=None): </ins><span class="cx"> for rule in self.syncrules: </span><span class="cx"> rule.execute(source, dest, obj, child, clearkeys) </span><span class="cx"> </span><span class="lines">@@ -110,7 +109,7 @@ </span><span class="cx"> if isinstance(dest, dict): </span><span class="cx"> dest[self.dest_column.key] = value </span><span class="cx"> else: </span><del>- #print "SYNC VALUE", value, "TO", dest </del><ins>+ #print "SYNC VALUE", value, "TO", dest, self.source_column, self.dest_column </ins><span class="cx"> self.dest_mapper._setattrbycolumn(dest, self.dest_column, value) </span><span class="cx"> </span><span class="cx"> class BinaryVisitor(sql.ClauseVisitor): </span></span></pre></div> <a id="sqlalchemytrunktestinheritancepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/test/inheritance.py (1053 => 1054)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/test/inheritance.py 2006-02-26 21:45:10 UTC (rev 1053) +++ sqlalchemy/trunk/test/inheritance.py 2006-02-26 22:23:01 UTC (rev 1054) </span><span class="lines">@@ -127,8 +127,10 @@ </span><span class="cx"> return "Bar(%s)" % self.data </span><span class="cx"> </span><span class="cx"> Bar.mapper = mapper(Bar, bar, inherits=Foo.mapper, properties = { </span><del>- # TODO: use syncrules for this - 'id':[bar.c.bid, foo.c.id] </del><ins>+ # 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] </ins><span class="cx"> }) </span><span class="cx"> </span><span class="cx"> 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)) </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-02-26 21:45: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>[1053] sqlalchemy/trunk/test: factored out "syncrule" logic to a separate package, so mapper will be able to make use of it as well as properties.</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1053</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-02-26 15:45:10 -0600 (Sun, 26 Feb 2006)</dd> </dl> <h3>Log Message</h3> <pre>factored out "syncrule" logic to a separate package, so mapper will be able to make use of it as well as properties. also clarifies the "synchronization" idea</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunklibsqlalchemymappingobjectstorepy">sqlalchemy/trunk/lib/sqlalchemy/mapping/objectstore.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemymappingpropertiespy">sqlalchemy/trunk/lib/sqlalchemy/mapping/properties.py</a></li> <li><a href="#sqlalchemytrunktestinheritancepy">sqlalchemy/trunk/test/inheritance.py</a></li> </ul> <h3>Added Paths</h3> <ul> <li><a href="#sqlalchemytrunklibsqlalchemymappingsyncpy">sqlalchemy/trunk/lib/sqlalchemy/mapping/sync.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunklibsqlalchemymappingobjectstorepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/mapping/objectstore.py (1052 => 1053)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/mapping/objectstore.py 2006-02-26 21:39:14 UTC (rev 1052) +++ sqlalchemy/trunk/lib/sqlalchemy/mapping/objectstore.py 2006-02-26 21:45:10 UTC (rev 1053) </span><span class="lines">@@ -352,7 +352,7 @@ </span><span class="cx"> </span><span class="cx"> def register_callable(self, obj, key, func, uselist, **kwargs): </span><span class="cx"> self.attributes.set_callable(obj, key, func, uselist, **kwargs) </span><del>- </del><ins>+ </ins><span class="cx"> def register_clean(self, obj): </span><span class="cx"> try: </span><span class="cx"> del self.dirty[obj] </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemymappingpropertiespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/mapping/properties.py (1052 => 1053)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/mapping/properties.py 2006-02-26 21:39:14 UTC (rev 1052) +++ sqlalchemy/trunk/lib/sqlalchemy/mapping/properties.py 2006-02-26 21:45:10 UTC (rev 1053) </span><span class="lines">@@ -14,6 +14,7 @@ </span><span class="cx"> import sqlalchemy.engine as engine </span><span class="cx"> import sqlalchemy.util as util </span><span class="cx"> import sqlalchemy.attributes as attributes </span><ins>+import sync </ins><span class="cx"> import mapper </span><span class="cx"> import objectstore </span><span class="cx"> from sqlalchemy.exceptions import * </span><span class="lines">@@ -202,7 +203,15 @@ </span><span class="cx"> if self.backref is not None: </span><span class="cx"> # try to set a LazyLoader on our mapper referencing the parent mapper </span><span class="cx"> if not self.mapper.props.has_key(self.backref): </span><del>- self.mapper.add_property(self.backref, LazyLoader(self.parent, self.secondary, self.primaryjoin, self.secondaryjoin, backref=self.key, is_backref=True)); </del><ins>+ if self.secondaryjoin is not None: + # if setting up a backref to a many-to-many, reverse the order + # of the "primary" and "secondary" joins + pj = self.secondaryjoin + sj = self.primaryjoin + else: + pj = self.primaryjoin + sj = None + self.mapper.add_property(self.backref, LazyLoader(self.parent, self.secondary, pj, sj, backref=self.key, is_backref=True)); </ins><span class="cx"> else: </span><span class="cx"> # else set one of us as the "backreference" </span><span class="cx"> if not self.mapper.props[self.backref].is_backref: </span><span class="lines">@@ -525,71 +534,17 @@ </span><span class="cx"> The list of rules is used within commits by the _synchronize() method when dependent </span><span class="cx"> objects are processed.""" </span><span class="cx"> </span><del>- SyncRule = PropertyLoader.SyncRule - </del><span class="cx"> parent_tables = util.HashSet(self.parent.tables + [self.parent.primarytable]) </span><span class="cx"> target_tables = util.HashSet(self.mapper.tables + [self.mapper.primarytable]) </span><span class="cx"> </span><del>- def check_for_table(binary, l): - for col in [binary.left, binary.right]: - if col.table in l: - return col - else: - return None - - def compile(binary): - """assembles a SyncRule given a single binary condition""" - if binary.operator != '=' or not isinstance(binary.left, schema.Column) or not isinstance(binary.right, schema.Column): - return </del><ins>+ self.syncrules = sync.ClauseSynchronizer(self.parent, self.mapper, self.direction) + if self.direction == PropertyLoader.MANYTOMANY: + #print "COMPILING p/c", self.parent, self.mapper + self.syncrules.compile(self.primaryjoin, parent_tables, [self.secondary], False) + self.syncrules.compile(self.secondaryjoin, target_tables, [self.secondary], True) + else: + self.syncrules.compile(self.primaryjoin, parent_tables, target_tables) </ins><span class="cx"> </span><del>- if binary.left.table == binary.right.table: - # self-cyclical relation - if binary.left.primary_key: - source = binary.left - dest = binary.right - elif binary.right.primary_key: - source = binary.right - dest = binary.left - else: - raise ArgumentError("Cant determine direction for relationship %s = %s" % (binary.left.fullname, binary.right.fullname)) - if self.direction == PropertyLoader.ONETOMANY: - self.syncrules.append(SyncRule(self.parent, source, dest, dest_mapper=self.mapper)) - elif self.direction == PropertyLoader.MANYTOONE: - self.syncrules.append(SyncRule(self.mapper, source, dest, dest_mapper=self.parent)) - else: - raise AssertionError("assert failed") - else: - pt = check_for_table(binary, parent_tables) - tt = check_for_table(binary, target_tables) - st = check_for_table(binary, [self.secondary]) - #print "parenttable", [t.name for t in parent_tables] - #print "ttable", [t.name for t in target_tables] - #print "OK", str(binary), pt, tt, st - if pt and tt: - if self.direction == PropertyLoader.ONETOMANY: - self.syncrules.append(SyncRule(self.parent, pt, tt, dest_mapper=self.mapper)) - elif self.direction == PropertyLoader.MANYTOONE: - self.syncrules.append(SyncRule(self.mapper, tt, pt, dest_mapper=self.parent)) - else: - if visiting is self.primaryjoin: - self.syncrules.append(SyncRule(self.parent, pt, st, direction=PropertyLoader.ONETOMANY)) - else: - self.syncrules.append(SyncRule(self.mapper, tt, st, direction=PropertyLoader.MANYTOONE)) - elif pt and st: - self.syncrules.append(SyncRule(self.parent, pt, st, direction=PropertyLoader.ONETOMANY)) - elif tt and st: - self.syncrules.append(SyncRule(self.mapper, tt, st, direction=PropertyLoader.MANYTOONE)) - - self.syncrules = [] - processor = BinaryVisitor(compile) - visiting = self.primaryjoin - self.primaryjoin.accept_visitor(processor) - if self.secondaryjoin is not None: - visiting = self.secondaryjoin - self.secondaryjoin.accept_visitor(processor) - if len(self.syncrules) == 0: - raise ArgumentError("No syncrules generated for join criterion " + str(self.primaryjoin)) - </del><span class="cx"> def _synchronize(self, obj, child, associationrow, clearkeys): </span><span class="cx"> """called during a commit to execute the full list of syncrules on the </span><span class="cx"> given object/child/optional association row""" </span><span class="lines">@@ -606,54 +561,8 @@ </span><span class="cx"> if dest is None: </span><span class="cx"> return </span><span class="cx"> </span><del>- for rule in self.syncrules: - rule.execute(source, dest, obj, child, clearkeys) </del><ins>+ self.syncrules.execute(source, dest, obj, child, clearkeys) </ins><span class="cx"> </span><del>- class SyncRule(object): - """An instruction indicating how to populate the objects on each side of a relationship. - i.e. if table1 column A is joined against - table2 column B, and we are a one-to-many from table1 to table2, a syncrule would say - 'take the A attribute from object1 and assign it to the B attribute on object2'. - - A rule contains the source mapper, the source column, destination column, - destination mapper in the case of a one/many relationship, and - the integer direction of this mapper relative to the association in the case - of a many to many relationship. - """ - def __init__(self, source_mapper, source_column, dest_column, dest_mapper=None, direction=None): - self.source_mapper = source_mapper - self.source_column = source_column - self.direction = direction - self.dest_mapper = dest_mapper - self.dest_column = dest_column - #print "SyncRule", source_mapper, source_column, dest_column, dest_mapper, direction - - def execute(self, source, dest, obj, child, clearkeys): - if self.direction is not None: - self.exec_many2many(dest, obj, child, clearkeys) - else: - self.exec_one2many(source, dest, clearkeys) - - def exec_many2many(self, destination, obj, child, clearkeys): - if self.direction == PropertyLoader.ONETOMANY: - source = obj - elif self.direction == PropertyLoader.MANYTOONE: - source = child - if clearkeys: - value = None - else: - value = self.source_mapper._getattrbycolumn(source, self.source_column) - destination[self.dest_column.key] = value - - def exec_one2many(self, source, destination, clearkeys): - if clearkeys or source is None: - value = None - else: - value = self.source_mapper._getattrbycolumn(source, self.source_column) - #print "SYNC VALUE", value, "TO", destination - self.dest_mapper._setattrbycolumn(destination, self.dest_column, value) - - </del><span class="cx"> class LazyLoader(PropertyLoader): </span><span class="cx"> def do_init_subclass(self, key, parent): </span><span class="cx"> (self.lazywhere, self.lazybinds) = create_lazy_clause(self.parent.table, self.primaryjoin, self.secondaryjoin, self.foreignkey) </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemymappingsyncpy"></a> <div class="addfile"><h4>Added: sqlalchemy/trunk/lib/sqlalchemy/mapping/sync.py (1052 => 1053)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/mapping/sync.py 2006-02-26 21:39:14 UTC (rev 1052) +++ sqlalchemy/trunk/lib/sqlalchemy/mapping/sync.py 2006-02-26 21:45:10 UTC (rev 1053) </span><span class="lines">@@ -0,0 +1,121 @@ </span><ins>+import sqlalchemy.sql as sql +import sqlalchemy.schema as schema +from sqlalchemy.exceptions import * +import properties + +"""contains the ClauseSynchronizer class which is used to map attributes between two objects +in a manner corresponding to a SQL clause that compares column values.""" + +ONETOMANY = 0 +MANYTOONE = 1 +MANYTOMANY = 2 + +class ClauseSynchronizer(object): + """Given a SQL clause, usually a series of one or more binary + expressions between columns, and a set of 'source' and 'destination' mappers, compiles a set of SyncRules + corresponding to that information. The ClauseSynchronizer can then be executed given a set of parent/child + objects or destination dictionary, which will iterate through each of its SyncRules and execute them. + Each SyncRule will copy the value of a single attribute from the parent + to the child, corresponding to the pair of columns in a particular binary expression, using the source and + destination mappers to map those two columns to object attributes within parent and child.""" + def __init__(self, parent_mapper, child_mapper, direction): + self.parent_mapper = parent_mapper + self.child_mapper = child_mapper + self.direction = direction + self.syncrules = [] + + def compile(self, sqlclause, source_tables, target_tables, issecondary=None): + def check_for_table(binary, l): + for col in [binary.left, binary.right]: + if col.table in l: + return col + else: + return None + + def compile_binary(binary): + """assembles a SyncRule given a single binary condition""" + if binary.operator != '=' or not isinstance(binary.left, schema.Column) or not isinstance(binary.right, schema.Column): + return + + if binary.left.table == binary.right.table: + # self-cyclical relation + if binary.left.primary_key: + source = binary.left + dest = binary.right + elif binary.right.primary_key: + source = binary.right + dest = binary.left + else: + raise ArgumentError("Cant determine direction for relationship %s = %s" % (binary.left.fullname, binary.right.fullname)) + if self.direction == ONETOMANY: + self.syncrules.append(SyncRule(self.parent_mapper, source, dest, dest_mapper=self.child_mapper)) + elif self.direction == MANYTOONE: + self.syncrules.append(SyncRule(self.child_mapper, source, dest, dest_mapper=self.parent_mapper)) + else: + raise AssertionError("assert failed") + else: + pt = check_for_table(binary, source_tables) + tt = check_for_table(binary, target_tables) + #print "OK", binary, [t.name for t in source_tables], [t.name for t in target_tables] + if pt and tt: + if self.direction == ONETOMANY: + self.syncrules.append(SyncRule(self.parent_mapper, pt, tt, dest_mapper=self.child_mapper)) + elif self.direction == MANYTOONE: + self.syncrules.append(SyncRule(self.child_mapper, tt, pt, dest_mapper=self.parent_mapper)) + else: + if not issecondary: + self.syncrules.append(SyncRule(self.parent_mapper, pt, tt, dest_mapper=self.child_mapper, issecondary=issecondary)) + else: + self.syncrules.append(SyncRule(self.child_mapper, pt, tt, dest_mapper=self.parent_mapper, issecondary=issecondary)) + + rules_added = len(self.syncrules) + processor = BinaryVisitor(compile_binary) + sqlclause.accept_visitor(processor) + if len(self.syncrules) == rules_added: + raise ArgumentError("No syncrules generated for join criterion " + str(sqlclause)) + + def execute(self, source, dest, obj, child, clearkeys): + for rule in self.syncrules: + rule.execute(source, dest, obj, child, clearkeys) + +class SyncRule(object): + """An instruction indicating how to populate the objects on each side of a relationship. + i.e. if table1 column A is joined against + table2 column B, and we are a one-to-many from table1 to table2, a syncrule would say + 'take the A attribute from object1 and assign it to the B attribute on object2'. + + A rule contains the source mapper, the source column, destination column, + destination mapper in the case of a one/many relationship, and + the integer direction of this mapper relative to the association in the case + of a many to many relationship. + """ + def __init__(self, source_mapper, source_column, dest_column, dest_mapper=None, issecondary=None): + self.source_mapper = source_mapper + self.source_column = source_column + self.issecondary = issecondary + self.dest_mapper = dest_mapper + self.dest_column = dest_column + #print "SyncRule", source_mapper, source_column, dest_column, dest_mapper, direction + + def execute(self, source, dest, obj, child, clearkeys): + if source is None: + if self.issecondary is False: + source = obj + elif self.issecondary is True: + source = child + if clearkeys or source is None: + value = None + else: + value = self.source_mapper._getattrbycolumn(source, self.source_column) + if isinstance(dest, dict): + dest[self.dest_column.key] = value + else: + #print "SYNC VALUE", value, "TO", dest + self.dest_mapper._setattrbycolumn(dest, self.dest_column, value) + +class BinaryVisitor(sql.ClauseVisitor): + def __init__(self, func): + self.func = func + def visit_binary(self, binary): + self.func(binary) + </ins></span></pre></div> <a id="sqlalchemytrunktestinheritancepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/test/inheritance.py (1052 => 1053)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/test/inheritance.py 2006-02-26 21:39:14 UTC (rev 1052) +++ sqlalchemy/trunk/test/inheritance.py 2006-02-26 21:45:10 UTC (rev 1053) </span><span class="lines">@@ -90,65 +90,67 @@ </span><span class="cx"> objectstore.commit() </span><span class="cx"> </span><span class="cx"> class InheritTest2(testbase.AssertMixin): </span><del>- def setUpAll(self): - engine = testbase.db - global foo, bar, foo_bar - foo = Table('foo', engine, - Column('id', Integer, primary_key=True), - Column('data', String(20)), - ).create() </del><ins>+ def setUpAll(self): + engine = testbase.db + global foo, bar, foo_bar + foo = Table('foo', engine, + Column('id', Integer, primary_key=True), + Column('data', String(20)), + ).create() </ins><span class="cx"> </span><del>- bar = Table('bar', engine, - Column('bid', Integer, ForeignKey('foo.id'), primary_key=True), - #Column('fid', Integer, ForeignKey('foo.id'), ) - ).create() </del><ins>+ bar = Table('bar', engine, + Column('bid', Integer, ForeignKey('foo.id'), primary_key=True), + #Column('fid', Integer, ForeignKey('foo.id'), ) + ).create() </ins><span class="cx"> </span><del>- foo_bar = Table('foo_bar', engine, - Column('foo_id', Integer, ForeignKey('foo.id')), - Column('bar_id', Integer, ForeignKey('bar.bid'))).create() </del><ins>+ foo_bar = Table('foo_bar', engine, + Column('foo_id', Integer, ForeignKey('foo.id')), + Column('bar_id', Integer, ForeignKey('bar.bid'))).create() </ins><span class="cx"> </span><del>- def tearDownAll(self): - foo_bar.drop() - bar.drop() - foo.drop() </del><ins>+ def tearDownAll(self): + foo_bar.drop() + bar.drop() + foo.drop() </ins><span class="cx"> </span><del>- def testbasic(self): - class Foo(object): - def __init__(self, data=None): - self.data = data - def __str__(self): - return "Foo(%s)" % self.data - def __repr__(self): - return str(self) </del><ins>+ def testbasic(self): + class Foo(object): + def __init__(self, data=None): + self.data = data + def __str__(self): + return "Foo(%s)" % self.data + def __repr__(self): + return str(self) </ins><span class="cx"> </span><del>- Foo.mapper = mapper(Foo, foo) - class Bar(Foo): - def __str__(self): - return "Bar(%s)" % self.data </del><ins>+ Foo.mapper = mapper(Foo, foo) + class Bar(Foo): + def __str__(self): + return "Bar(%s)" % self.data </ins><span class="cx"> </span><del>- Bar.mapper = mapper(Bar, bar, inherits=Foo.mapper, properties = { - # TODO: use syncrules for this - 'id':[bar.c.bid, foo.c.id] - }) </del><ins>+ Bar.mapper = mapper(Bar, bar, inherits=Foo.mapper, properties = { + # TODO: use syncrules for this + 'id':[bar.c.bid, foo.c.id] + }) </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)) </del><ins>+ 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)) </ins><span class="cx"> </span><ins>+ b = Bar('barfoo') + objectstore.commit() </ins><span class="cx"> </span><del>- b = Bar('barfoo') - objectstore.commit() </del><ins>+ b.foos.append(Foo('subfoo1')) + b.foos.append(Foo('subfoo2')) </ins><span class="cx"> </span><ins>+ objectstore.commit() + objectstore.clear() </ins><span class="cx"> </span><del>- b.foos.append(Foo('subfoo1')) - b.foos.append(Foo('subfoo2')) </del><ins>+ l =b.mapper.select() + print l[0] + print l[0].foos + self.assert_result(l, Bar, +# {'id':1, 'data':'barfoo', 'bid':1, 'foos':(Foo, [{'id':2,'data':'subfoo1'}, {'id':3,'data':'subfoo2'}])}, + {'id':1, 'data':'barfoo', 'foos':(Foo, [{'id':2,'data':'subfoo1'}, {'id':3,'data':'subfoo2'}])}, + ) </ins><span class="cx"> </span><del>- objectstore.commit() - objectstore.clear() </del><span class="cx"> </span><del>- l =b.mapper.select() - print l[0] - print l[0].foos - - </del><span class="cx"> if __name__ == "__main__": </span><span class="cx"> testbase.main() </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>[1052] sqlalchemy/trunk/lib/sqlalchemy/mapping/mapper.py: place _instance_key on object only when objectstore finally register_clean's on it, to make</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1052</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-02-26 15:39:14 -0600 (Sun, 26 Feb 2006)</dd> </dl> <h3>Log Message</h3> <pre>place _instance_key on object only when objectstore finally register_clean's on it, to make room for more aggressive "identity map" assertion when modifying objects incoming from a result set</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunklibsqlalchemymappingmapperpy">sqlalchemy/trunk/lib/sqlalchemy/mapping/mapper.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunklibsqlalchemymappingmapperpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/mapping/mapper.py (1051 => 1052)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/mapping/mapper.py 2006-02-26 20:15:02 UTC (rev 1051) +++ sqlalchemy/trunk/lib/sqlalchemy/mapping/mapper.py 2006-02-26 21:39:14 UTC (rev 1052) </span><span class="lines">@@ -724,8 +724,6 @@ </span><span class="cx"> instance = self.extension.create_instance(self, row, imap, self.class_) </span><span class="cx"> if instance is None: </span><span class="cx"> instance = self.class_(_mapper_nohistory=True) </span><del>- instance._instance_key = identitykey - </del><span class="cx"> imap[identitykey] = instance </span><span class="cx"> isnew = True </span><span class="cx"> else: </span><span class="lines">@@ -742,7 +740,7 @@ </span><span class="cx"> if self.extension.append_result(self, row, imap, result, instance, isnew, populate_existing=populate_existing): </span><span class="cx"> if result is not None: </span><span class="cx"> result.append_nohistory(instance) </span><del>- </del><ins>+ </ins><span class="cx"> return instance </span><span class="cx"> </span><span class="cx"> class MapperProperty(object): </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-02-26 20:15: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>[1051] sqlalchemy/trunk/lib/sqlalchemy/databases/postgres.py: postgres wraps exec's in SQLError catch</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1051</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-02-26 14:15:02 -0600 (Sun, 26 Feb 2006)</dd> </dl> <h3>Log Message</h3> <pre>postgres wraps exec's in SQLError catch</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunklibsqlalchemydatabasespostgrespy">sqlalchemy/trunk/lib/sqlalchemy/databases/postgres.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunklibsqlalchemydatabasespostgrespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/databases/postgres.py (1050 => 1051)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/databases/postgres.py 2006-02-26 19:15:43 UTC (rev 1050) +++ sqlalchemy/trunk/lib/sqlalchemy/databases/postgres.py 2006-02-26 20:15:02 UTC (rev 1051) </span><span class="lines">@@ -248,7 +248,10 @@ </span><span class="cx"> to produce this correctly for an executemany, so we do our own executemany here.""" </span><span class="cx"> rowcount = 0 </span><span class="cx"> for param in parameters: </span><del>- c.execute(statement, param) </del><ins>+ try: + c.execute(statement, param) + except Exception, e: + raise exceptions.SQLError(statement, param, e) </ins><span class="cx"> rowcount += c.rowcount </span><span class="cx"> self.context.rowcount = rowcount </span><span class="cx"> </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-02-26 19:15:52
|
<!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>[1050] sqlalchemy/trunk: register_deleted/register_dirty perform pre-check before doing the "validate" operation to cut down on method overhaed</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1050</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-02-26 13:15:43 -0600 (Sun, 26 Feb 2006)</dd> </dl> <h3>Log Message</h3> <pre>register_deleted/register_dirty perform pre-check before doing the "validate" operation to cut down on method overhaed</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunkCHANGES">sqlalchemy/trunk/CHANGES</a></li> <li><a href="#sqlalchemytrunklibsqlalchemymappingobjectstorepy">sqlalchemy/trunk/lib/sqlalchemy/mapping/objectstore.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunkCHANGES"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/CHANGES (1049 => 1050)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/CHANGES 2006-02-26 19:09:42 UTC (rev 1049) +++ sqlalchemy/trunk/CHANGES 2006-02-26 19:15:43 UTC (rev 1050) </span><span class="lines">@@ -5,6 +5,10 @@ </span><span class="cx"> - overhaul to sql/schema packages so that the sql package can run all on its own, </span><span class="cx"> producing selects, inserts, etc. without any engine dependencies. Table/Column </span><span class="cx"> are the "physical" subclasses of TableClause/ColumnClause. </span><ins>+- fixes to mapper inheritance, involving properties that relate to the same table +involved in the mapper inheritance scheme +- made objectstore "check for out-of-identitymap" more aggressive, will perform the +check when object attributes are modified or the object is deleted </ins><span class="cx"> 0.1.2 </span><span class="cx"> - fixed a recursive call in schema that was somehow running 994 times then returning </span><span class="cx"> normally. broke nothing, slowed down everything. thanks to jpellerin for finding this. </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemymappingobjectstorepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/mapping/objectstore.py (1049 => 1050)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/mapping/objectstore.py 2006-02-26 19:09:42 UTC (rev 1049) +++ sqlalchemy/trunk/lib/sqlalchemy/mapping/objectstore.py 2006-02-26 19:15:43 UTC (rev 1050) </span><span class="lines">@@ -372,8 +372,9 @@ </span><span class="cx"> self.new.append(obj) </span><span class="cx"> </span><span class="cx"> def register_dirty(self, obj): </span><del>- self._validate_obj(obj) - self.dirty.append(obj) </del><ins>+ if not self.dirty.contains(obj): + self._validate_obj(obj) + self.dirty.append(obj) </ins><span class="cx"> </span><span class="cx"> def is_dirty(self, obj): </span><span class="cx"> if not self.dirty.contains(obj): </span><span class="lines">@@ -382,12 +383,13 @@ </span><span class="cx"> return True </span><span class="cx"> </span><span class="cx"> def register_deleted(self, obj): </span><del>- self._validate_obj(obj) - self.deleted.append(obj) - mapper = object_mapper(obj) - # TODO: should the cascading delete dependency thing - # happen wtihin PropertyLoader.process_dependencies ? - mapper.register_deleted(obj, self) </del><ins>+ if not self.deleted.contains(obj): + self._validate_obj(obj) + self.deleted.append(obj) + mapper = object_mapper(obj) + # TODO: should the cascading delete dependency thing + # happen wtihin PropertyLoader.process_dependencies ? + mapper.register_deleted(obj, self) </ins><span class="cx"> </span><span class="cx"> def unregister_deleted(self, obj): </span><span class="cx"> try: </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-02-26 19:09:52
|
<!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>[1049] sqlalchemy/trunk/lib/sqlalchemy/mapping/objectstore.py: fixed exception import.</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1049</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-02-26 13:09:42 -0600 (Sun, 26 Feb 2006)</dd> </dl> <h3>Log Message</h3> <pre>fixed exception import. check for objects being present in the identity map occurs not just at commit time but also when its logged as "dirty" or "deleted".</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunklibsqlalchemymappingobjectstorepy">sqlalchemy/trunk/lib/sqlalchemy/mapping/objectstore.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunklibsqlalchemymappingobjectstorepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/mapping/objectstore.py (1048 => 1049)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/mapping/objectstore.py 2006-02-26 18:34:20 UTC (rev 1048) +++ sqlalchemy/trunk/lib/sqlalchemy/mapping/objectstore.py 2006-02-26 19:09:42 UTC (rev 1049) </span><span class="lines">@@ -13,6 +13,7 @@ </span><span class="cx"> import sqlalchemy </span><span class="cx"> import sqlalchemy.util as util </span><span class="cx"> import sqlalchemy.attributes as attributes </span><ins>+from sqlalchemy.exceptions import * </ins><span class="cx"> import topological </span><span class="cx"> import weakref </span><span class="cx"> import string </span><span class="lines">@@ -333,6 +334,12 @@ </span><span class="cx"> pass </span><span class="cx"> self.attributes.commit(obj) </span><span class="cx"> self.attributes.remove(obj) </span><ins>+ + def _validate_obj(self, obj): + """validates that dirty/delete/commit operations can occur upon the given object, by checking + if it has an instance key and that the instance key is present in the identity map.""" + if hasattr(obj, '_instance_key') and not self.identity_map.has_key(obj._instance_key): + raise InvalidRequestError("Detected a mapped object not present in the current thread's Identity Map: '%s'. Use objectstore.import_instance() to place deserialized instances or instances from other threads" % repr(obj._instance_key)) </ins><span class="cx"> </span><span class="cx"> def update(self, obj): </span><span class="cx"> """called to add an object to this UnitOfWork as though it were loaded from the DB, </span><span class="lines">@@ -365,6 +372,7 @@ </span><span class="cx"> self.new.append(obj) </span><span class="cx"> </span><span class="cx"> def register_dirty(self, obj): </span><ins>+ self._validate_obj(obj) </ins><span class="cx"> self.dirty.append(obj) </span><span class="cx"> </span><span class="cx"> def is_dirty(self, obj): </span><span class="lines">@@ -374,6 +382,7 @@ </span><span class="cx"> return True </span><span class="cx"> </span><span class="cx"> def register_deleted(self, obj): </span><ins>+ self._validate_obj(obj) </ins><span class="cx"> self.deleted.append(obj) </span><span class="cx"> mapper = object_mapper(obj) </span><span class="cx"> # TODO: should the cascading delete dependency thing </span><span class="lines">@@ -469,8 +478,7 @@ </span><span class="cx"> #print "REGISTER", repr(obj), repr(getattr(obj, '_instance_key', None)), str(isdelete), str(listonly) </span><span class="cx"> # things can get really confusing if theres duplicate instances floating around, </span><span class="cx"> # so make sure everything is OK </span><del>- if hasattr(obj, '_instance_key') and not self.uow.identity_map.has_key(obj._instance_key): - raise InvalidRequestError("Detected a mapped object not present in the current thread's Identity Map: '%s'. Use objectstore.import_instance() to place deserialized instances or instances from other threads" % repr(obj._instance_key)) </del><ins>+ self.uow._validate_obj(obj) </ins><span class="cx"> </span><span class="cx"> mapper = object_mapper(obj) </span><span class="cx"> self.mappers.append(mapper) </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-02-26 18:34: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>[1048] sqlalchemy/branches/indexes/test: Add support for inline index syntax outlined in #6</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1048</dd> <dt>Author</dt> <dd>jpellerin</dd> <dt>Date</dt> <dd>2006-02-26 12:34:20 -0600 (Sun, 26 Feb 2006)</dd> </dl> <h3>Log Message</h3> <pre>Add support for inline index syntax outlined in #6</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesindexeslibsqlalchemyansisqlpy">sqlalchemy/branches/indexes/lib/sqlalchemy/ansisql.py</a></li> <li><a href="#sqlalchemybranchesindexeslibsqlalchemydatabasessqlitepy">sqlalchemy/branches/indexes/lib/sqlalchemy/databases/sqlite.py</a></li> <li><a href="#sqlalchemybranchesindexeslibsqlalchemyschemapy">sqlalchemy/branches/indexes/lib/sqlalchemy/schema.py</a></li> <li><a href="#sqlalchemybranchesindexeslibsqlalchemysqlpy">sqlalchemy/branches/indexes/lib/sqlalchemy/sql.py</a></li> <li><a href="#sqlalchemybranchesindexestestindexespy">sqlalchemy/branches/indexes/test/indexes.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesindexeslibsqlalchemyansisqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/indexes/lib/sqlalchemy/ansisql.py (1047 => 1048)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/indexes/lib/sqlalchemy/ansisql.py 2006-02-26 18:04:14 UTC (rev 1047) +++ sqlalchemy/branches/indexes/lib/sqlalchemy/ansisql.py 2006-02-26 18:34:20 UTC (rev 1048) </span><span class="lines">@@ -517,8 +517,11 @@ </span><span class="cx"> self.append("\tPRIMARY KEY (%s)" % string.join([c.name for c in pks],', ')) </span><span class="cx"> </span><span class="cx"> self.append("\n)%s\n\n" % self.post_create_table(table)) </span><del>- self.execute() - </del><ins>+ self.execute() + if hasattr(table, 'indexes'): + for index in table.indexes: + self.visit_index(index) + </ins><span class="cx"> def post_create_table(self, table): </span><span class="cx"> return '' </span><span class="cx"> </span><span class="lines">@@ -550,6 +553,8 @@ </span><span class="cx"> self.execute() </span><span class="cx"> </span><span class="cx"> def visit_table(self, table): </span><ins>+ # NOTE: indexes on the table will be automatically dropped, so + # no need to drop them individually </ins><span class="cx"> self.append("\nDROP TABLE " + table.fullname) </span><span class="cx"> self.execute() </span><span class="cx"> </span></span></pre></div> <a id="sqlalchemybranchesindexeslibsqlalchemydatabasessqlitepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/indexes/lib/sqlalchemy/databases/sqlite.py (1047 => 1048)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/indexes/lib/sqlalchemy/databases/sqlite.py 2006-02-26 18:04:14 UTC (rev 1047) +++ sqlalchemy/branches/indexes/lib/sqlalchemy/databases/sqlite.py 2006-02-26 18:34:20 UTC (rev 1048) </span><span class="lines">@@ -260,6 +260,9 @@ </span><span class="cx"> self.append("\tUNIQUE (%s)" % string.join([c.name for c in table.primary_key],', ')) </span><span class="cx"> </span><span class="cx"> self.append("\n)\n\n") </span><del>- self.execute() </del><ins>+ self.execute() + if hasattr(table, 'indexes'): + for index in table.indexes: + self.visit_index(index) </ins><span class="cx"> </span><span class="cx"> </span></span></pre></div> <a id="sqlalchemybranchesindexeslibsqlalchemyschemapy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/indexes/lib/sqlalchemy/schema.py (1047 => 1048)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/indexes/lib/sqlalchemy/schema.py 2006-02-26 18:04:14 UTC (rev 1047) +++ sqlalchemy/branches/indexes/lib/sqlalchemy/schema.py 2006-02-26 18:34:20 UTC (rev 1048) </span><span class="lines">@@ -160,7 +160,10 @@ </span><span class="cx"> self.primary_key.append(column) </span><span class="cx"> column.table = self </span><span class="cx"> column.type = self.engine.type_descriptor(column.type) </span><del>- </del><ins>+ + def append_index(self, index): + self.indexes[index.name] = index + </ins><span class="cx"> def _set_parent(self, schema): </span><span class="cx"> schema.tables[self.name] = self </span><span class="cx"> self.schema = schema </span><span class="lines">@@ -170,6 +173,32 @@ </span><span class="cx"> for c in self.columns: </span><span class="cx"> c.accept_schema_visitor(visitor) </span><span class="cx"> return visitor.visit_table(self) </span><ins>+ + def append_index_column(self, column, index=None, unique=None): + """Add an index or a column to an existing index of the same name. + """ + if index is not None and unique is not None: + raise ValueError("index and unique may not both be specified") + if index: + if index is True: + name = 'ix_%s' % column.name + else: + name = index + elif unique: + if unique is True: + name = 'ux_%s' % column.name + else: + name = unique + # find this index in self.indexes + # add this column to it if found + # otherwise create new + try: + index = self.indexes[name] + index.append_column(column) + except KeyError: + index = Index(name, column, unique=unique) + return index + </ins><span class="cx"> def deregister(self): </span><span class="cx"> """removes this table from it's engines table registry. this does not </span><span class="cx"> issue a SQL DROP statement.""" </span><span class="lines">@@ -224,9 +253,22 @@ </span><span class="cx"> which will be invoked upon insert if this column is not present in the insert list or is given a value </span><span class="cx"> of None. </span><span class="cx"> </span><del>- hidden=False : indicates this column should not be listed in the table's list of columns. Used for the "oid" - column, which generally isnt in column lists. - """ </del><ins>+ hidden=False : indicates this column should not be listed in the + table's list of columns. Used for the "oid" column, which generally + isnt in column lists. + + index=None : True or index name. Indicates that this column is + indexed. Pass true to autogenerate the index name. Pass a string to + specify the index name. Multiple columns that specify the same index + name will all be included in the index, in the order of their + creation. + + unique=None : True or undex name. Indicates that this column is + indexed in a unique index . Pass true to autogenerate the index + name. Pass a string to specify the index name. Multiple columns that + specify the same index name will all be included in the index, in the + order of their creation. """ + </ins><span class="cx"> name = str(name) # in case of incoming unicode </span><span class="cx"> super(Column, self).__init__(name, None, type) </span><span class="cx"> self.args = args </span><span class="lines">@@ -235,6 +277,10 @@ </span><span class="cx"> self.nullable = kwargs.pop('nullable', not self.primary_key) </span><span class="cx"> self.hidden = kwargs.pop('hidden', False) </span><span class="cx"> self.default = kwargs.pop('default', None) </span><ins>+ self.index = kwargs.pop('index', None) + self.unique = kwargs.pop('unique', None) + if self.index is not None and self.unique is not None: + raise ArgumentError("Column may not define both index and unique") </ins><span class="cx"> self._foreign_key = None </span><span class="cx"> self._orig = None </span><span class="cx"> self._parent = None </span><span class="lines">@@ -269,6 +315,10 @@ </span><span class="cx"> if getattr(self, 'table', None) is not None: </span><span class="cx"> raise ArgumentError("this Column already has a table!") </span><span class="cx"> table.append_column(self) </span><ins>+ if self.index or self.unique: + table.append_index_column(self, index=self.index, + unique=self.unique) + </ins><span class="cx"> if self.default is not None: </span><span class="cx"> self.default = ColumnDefault(self.default) </span><span class="cx"> self._init_items(self.default) </span><span class="lines">@@ -429,7 +479,6 @@ </span><span class="cx"> class Index(SchemaItem): </span><span class="cx"> """Represents an index of columns from a database table </span><span class="cx"> """ </span><del>- </del><span class="cx"> def __init__(self, name, *columns, **kw): </span><span class="cx"> """Constructs an index object. Arguments are: </span><span class="cx"> </span><span class="lines">@@ -443,24 +492,34 @@ </span><span class="cx"> unique=True : create a unique index </span><span class="cx"> """ </span><span class="cx"> self.name = name </span><del>- self.columns = columns </del><ins>+ self.columns = [] + self.table = None </ins><span class="cx"> self.unique = kw.pop('unique', False) </span><del>- self._init_items() </del><ins>+ self._init_items(*columns) </ins><span class="cx"> </span><span class="cx"> engine = property(lambda s:s.table.engine) </span><del>- def _init_items(self): </del><ins>+ def _init_items(self, *args): + for column in args: + self.append_column(column) + + def append_column(self, column): </ins><span class="cx"> # make sure all columns are from the same table </span><del>- # FIXME: and no column is repeated - self.table = None - for column in self.columns: - if self.table is None: - self.table = column.table - elif column.table != self.table: - # all columns muse be from same table - raise ArgumentError("All index columns must be from same table. " - "%s is from %s not %s" % (column, - column.table, - self.table)) </del><ins>+ # and no column is repeated + if self.table is None: + self.table = column.table + self.table.append_index(self) + elif column.table != self.table: + # all columns muse be from same table + raise ArgumentError("All index columns must be from same table. " + "%s is from %s not %s" % (column, + column.table, + self.table)) + elif column.name in [ c.name for c in self.columns ]: + raise ArgumentError("A column may not appear twice in the " + "same index (%s already has column %s)" + % (self.name, column)) + self.columns.append(column) + </ins><span class="cx"> def create(self): </span><span class="cx"> self.engine.create(self) </span><span class="cx"> return self </span><span class="lines">@@ -481,11 +540,6 @@ </span><span class="cx"> class SchemaEngine(object): </span><span class="cx"> """a factory object used to create implementations for schema objects. This object </span><span class="cx"> is the ultimate base class for the engine.SQLEngine class.""" </span><del>- def indeximpl(self, index): - """returns a new implementation object for an Index (usually - sql.IndexImpl) - """ - raise NotImplementedError() </del><span class="cx"> def reflecttable(self, table): </span><span class="cx"> """given a table, will query the database and populate its Column and ForeignKey </span><span class="cx"> objects.""" </span><span class="lines">@@ -506,7 +560,7 @@ </span><span class="cx"> """visit a ForeignKey.""" </span><span class="cx"> pass </span><span class="cx"> def visit_index(self, index): </span><del>- """visit an Index (not implemented yet).""" </del><ins>+ """visit an Index.""" </ins><span class="cx"> pass </span><span class="cx"> def visit_passive_default(self, default): </span><span class="cx"> """visit a passive default""" </span></span></pre></div> <a id="sqlalchemybranchesindexeslibsqlalchemysqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/indexes/lib/sqlalchemy/sql.py (1047 => 1048)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/indexes/lib/sqlalchemy/sql.py 2006-02-26 18:04:14 UTC (rev 1047) +++ sqlalchemy/branches/indexes/lib/sqlalchemy/sql.py 2006-02-26 18:34:20 UTC (rev 1048) </span><span class="lines">@@ -982,11 +982,14 @@ </span><span class="cx"> super(TableClause, self).__init__(name) </span><span class="cx"> self.name = self.id = self.fullname = name </span><span class="cx"> self._columns = util.OrderedProperties() </span><ins>+ self._indexes = util.OrderedProperties() </ins><span class="cx"> self._foreign_keys = [] </span><span class="cx"> self._primary_key = [] </span><span class="cx"> for c in columns: </span><span class="cx"> self.append_column(c) </span><span class="cx"> </span><ins>+ indexes = property(lambda s:s._indexes) + </ins><span class="cx"> def append_column(self, c): </span><span class="cx"> self._columns[c.text] = c </span><span class="cx"> c.table = self </span></span></pre></div> <a id="sqlalchemybranchesindexestestindexespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/indexes/test/indexes.py (1047 => 1048)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/indexes/test/indexes.py 2006-02-26 18:04:14 UTC (rev 1047) +++ sqlalchemy/branches/indexes/test/indexes.py 2006-02-26 18:34:20 UTC (rev 1048) </span><span class="lines">@@ -6,8 +6,12 @@ </span><span class="cx"> </span><span class="cx"> def setUp(self): </span><span class="cx"> self.created = [] </span><del>- </del><ins>+ self.echo = testbase.db.echo + self.logger = testbase.db.logger + </ins><span class="cx"> def tearDown(self): </span><ins>+ testbase.db.echo = self.echo + testbase.db.logger = testbase.db.engine.logger = self.logger </ins><span class="cx"> if self.created: </span><span class="cx"> self.created.reverse() </span><span class="cx"> for entity in self.created: </span><span class="lines">@@ -26,11 +30,87 @@ </span><span class="cx"> employees.c.last_name, employees.c.first_name) </span><span class="cx"> i.create() </span><span class="cx"> self.created.append(i) </span><ins>+ assert employees.indexes['employee_name_index'] is i </ins><span class="cx"> </span><del>- i = Index('employee_email_index', - employees.c.email_address, unique=True) </del><ins>+ i2 = Index('employee_email_index', + employees.c.email_address, unique=True) + i2.create() + self.created.append(i2) + assert employees.indexes['employee_email_index'] is i2 + + def test_index_create_camelcase(self): + """test that mixed-case index identifiers are legal""" + employees = Table('companyEmployees', testbase.db, + Column('id', Integer, primary_key=True), + Column('firstName', String), + Column('lastName', String), + Column('emailAddress', String)) + employees.create() + self.created.append(employees) + + i = Index('employeeNameIndex', + employees.c.lastName, employees.c.firstName) </ins><span class="cx"> i.create() </span><span class="cx"> self.created.append(i) </span><span class="cx"> </span><ins>+ i = Index('employeeEmailIndex', + employees.c.emailAddress, unique=True) + i.create() + self.created.append(i) + + # Check that the table is useable. This is mostly for pg, + # which can be somewhat sticky with mixed-case identifiers + employees.insert().execute(firstName='Joe', lastName='Smith') + ss = employees.select().execute().fetchall() + assert ss[0].firstName == 'Joe' + assert ss[0].lastName == 'Smith' + + def test_index_create_inline(self): + """Test indexes defined with tables""" + + testbase.db.echo = True + capt = [] + class dummy: + pass + stream = dummy() + stream.write = capt.append + testbase.db.logger = testbase.db.engine.logger = stream + + events = Table('events', testbase.db, + Column('id', Integer, primary_key=True), + Column('name', String(30), unique=True), + Column('location', String(30), index=True), + Column('sport', String(30), + unique='sport_announcer'), + Column('announcer', String(30), + unique='sport_announcer'), + Column('winner', String(30), index='idx_winners')) + + index_names = [ ix.name for ix in events.indexes ] + assert 'ux_name' in index_names + assert 'ix_location' in index_names + assert 'sport_announcer' in index_names + assert 'idx_winners' in index_names + assert len(index_names) == 4 + + events.create() + self.created.append(events) + + # verify that the table is functional + events.insert().execute(id=1, name='hockey finals', location='rink', + sport='hockey', announcer='some canadian', + winner='sweden') + ss = events.select().execute().fetchall() + + assert capt[0].strip().startswith('CREATE TABLE events') + assert capt[2].strip() == \ + 'CREATE UNIQUE INDEX ux_name ON events (name)' + assert capt[4].strip() == \ + 'CREATE INDEX ix_location ON events (location)' + assert capt[6].strip() == \ + 'CREATE UNIQUE INDEX sport_announcer ON events (sport, announcer)' + assert capt[8].strip() == \ + 'CREATE INDEX idx_winners ON events (winner)' + </ins><span class="cx"> if __name__ == "__main__": </span><span class="cx"> testbase.main() </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-02-26 06:17: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>[1046] sqlalchemy/trunk/test/inheritance.py: added test to illustrate wacky inhertitance/many-to-many thing</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1046</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-02-26 00:17:21 -0600 (Sun, 26 Feb 2006)</dd> </dl> <h3>Log Message</h3> <pre>added test to illustrate wacky inhertitance/many-to-many thing</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunktestinheritancepy">sqlalchemy/trunk/test/inheritance.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunktestinheritancepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/test/inheritance.py (1045 => 1046)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/test/inheritance.py 2006-02-26 06:14:12 UTC (rev 1045) +++ sqlalchemy/trunk/test/inheritance.py 2006-02-26 06:17:21 UTC (rev 1046) </span><span class="lines">@@ -89,5 +89,66 @@ </span><span class="cx"> </span><span class="cx"> objectstore.commit() </span><span class="cx"> </span><ins>+class InheritTest2(testbase.AssertMixin): + def setUpAll(self): + engine = testbase.db + global foo, bar, foo_bar + foo = Table('foo', engine, + Column('id', Integer, primary_key=True), + Column('data', String(20)), + ).create() + + bar = Table('bar', engine, + Column('bid', Integer, ForeignKey('foo.id'), primary_key=True), + #Column('fid', Integer, ForeignKey('foo.id'), ) + ).create() + + foo_bar = Table('foo_bar', engine, + Column('foo_id', Integer, ForeignKey('foo.id')), + Column('bar_id', Integer, ForeignKey('bar.bid'))).create() + + def tearDownAll(self): + foo_bar.drop() + bar.drop() + foo.drop() + + def testbasic(self): + class Foo(object): + def __init__(self, data=None): + self.data = data + def __str__(self): + return "Foo(%s)" % self.data + def __repr__(self): + return str(self) + + Foo.mapper = mapper(Foo, foo) + class Bar(Foo): + def __str__(self): + return "Bar(%s)" % self.data + + Bar.mapper = mapper(Bar, bar, inherits=Foo.mapper, properties = { + # TODO: use syncrules for this + 'id':[bar.c.bid, foo.c.id] + }) + + 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.commit() + + + b.foos.append(Foo('subfoo1')) + b.foos.append(Foo('subfoo2')) + + objectstore.commit() + objectstore.clear() + + l =b.mapper.select() + print l[0] + print l[0].foos + + </ins><span class="cx"> if __name__ == "__main__": </span><span class="cx"> testbase.main() </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>[1045] sqlalchemy/trunk/test: adjustment to compile synchronizers which allows many-to-many synchronize to work even when one side of the relation has both tables in it (new unittest will be added to inheritance.py to show this...)</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1045</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-02-26 00:14:12 -0600 (Sun, 26 Feb 2006)</dd> </dl> <h3>Log Message</h3> <pre>adjustment to compile synchronizers which allows many-to-many synchronize to work even when one side of the relation has both tables in it (new unittest will be added to inheritance.py to show this...)</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunklibsqlalchemymappingpropertiespy">sqlalchemy/trunk/lib/sqlalchemy/mapping/properties.py</a></li> <li><a href="#sqlalchemytrunktestmapperpy">sqlalchemy/trunk/test/mapper.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunklibsqlalchemymappingpropertiespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/mapping/properties.py (1044 => 1045)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/mapping/properties.py 2006-02-26 02:25:42 UTC (rev 1044) +++ sqlalchemy/trunk/lib/sqlalchemy/mapping/properties.py 2006-02-26 06:14:12 UTC (rev 1045) </span><span class="lines">@@ -171,7 +171,6 @@ </span><span class="cx"> else: </span><span class="cx"> if self.primaryjoin is None: </span><span class="cx"> self.primaryjoin = sql.join(parent.table, self.target).onclause </span><del>- </del><span class="cx"> # if the foreign key wasnt specified and theres no assocaition table, try to figure </span><span class="cx"> # out who is dependent on who. we dont need all the foreign keys represented in the join, </span><span class="cx"> # just one of them. </span><span class="lines">@@ -572,7 +571,10 @@ </span><span class="cx"> elif self.direction == PropertyLoader.MANYTOONE: </span><span class="cx"> self.syncrules.append(SyncRule(self.mapper, tt, pt, dest_mapper=self.parent)) </span><span class="cx"> else: </span><del>- raise AssertionError("assert failed") </del><ins>+ if visiting is self.primaryjoin: + self.syncrules.append(SyncRule(self.parent, pt, st, direction=PropertyLoader.ONETOMANY)) + else: + self.syncrules.append(SyncRule(self.mapper, tt, st, direction=PropertyLoader.MANYTOONE)) </ins><span class="cx"> elif pt and st: </span><span class="cx"> self.syncrules.append(SyncRule(self.parent, pt, st, direction=PropertyLoader.ONETOMANY)) </span><span class="cx"> elif tt and st: </span><span class="lines">@@ -580,8 +582,10 @@ </span><span class="cx"> </span><span class="cx"> self.syncrules = [] </span><span class="cx"> processor = BinaryVisitor(compile) </span><ins>+ visiting = self.primaryjoin </ins><span class="cx"> self.primaryjoin.accept_visitor(processor) </span><span class="cx"> if self.secondaryjoin is not None: </span><ins>+ visiting = self.secondaryjoin </ins><span class="cx"> self.secondaryjoin.accept_visitor(processor) </span><span class="cx"> if len(self.syncrules) == 0: </span><span class="cx"> raise ArgumentError("No syncrules generated for join criterion " + str(self.primaryjoin)) </span><span class="lines">@@ -622,6 +626,7 @@ </span><span class="cx"> self.direction = direction </span><span class="cx"> self.dest_mapper = dest_mapper </span><span class="cx"> self.dest_column = dest_column </span><ins>+ #print "SyncRule", source_mapper, source_column, dest_column, dest_mapper, direction </ins><span class="cx"> </span><span class="cx"> def execute(self, source, dest, obj, child, clearkeys): </span><span class="cx"> if self.direction is not None: </span></span></pre></div> <a id="sqlalchemytrunktestmapperpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/test/mapper.py (1044 => 1045)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/test/mapper.py 2006-02-26 02:25:42 UTC (rev 1044) +++ sqlalchemy/trunk/test/mapper.py 2006-02-26 06:14:12 UTC (rev 1045) </span><span class="lines">@@ -254,6 +254,29 @@ </span><span class="cx"> au = AddressUser.mapper.get_by(user_name='jack') </span><span class="cx"> self.assert_(au.email_address == 'ja...@gm...') </span><span class="cx"> </span><ins>+ def testinherits2(self): + class _Order(object): + pass + class _Address(object): + pass + class AddressUser(_Address): + pass + assign_mapper(_Order, orders) + assign_mapper(_Address, addresses) + assign_mapper(AddressUser, users, inherits = _Address.mapper, + properties = { + 'orders' : relation(_Order.mapper, lazy=False) + }) + l = AddressUser.mapper.select() + jack = l[0] + self.assert_(jack.user_name=='jack') + jack.email_address = 'ja...@gm...' + objectstore.commit() + objectstore.clear() + au = AddressUser.mapper.get_by(user_name='jack') + self.assert_(au.email_address == 'ja...@gm...') + + </ins><span class="cx"> class DeferredTest(MapperSuperTest): </span><span class="cx"> </span><span class="cx"> def testbasic(self): </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-02-26 02:25:54
|
<!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>[1044] sqlalchemy/trunk/test: fixed ticket 72, where a copied clause was using the identical bind param object thereby screwing up a generated statement that included both the original clause and the copied clause, when positional parameters were used</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1044</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-02-25 20:25:42 -0600 (Sat, 25 Feb 2006)</dd> </dl> <h3>Log Message</h3> <pre>fixed ticket 72, where a copied clause was using the identical bind param object thereby screwing up a generated statement that included both the original clause and the copied clause, when positional parameters were used</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunklibsqlalchemysqlpy">sqlalchemy/trunk/lib/sqlalchemy/sql.py</a></li> <li><a href="#sqlalchemytrunktestmanytomanypy">sqlalchemy/trunk/test/manytomany.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunklibsqlalchemysqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/sql.py (1043 => 1044)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/sql.py 2006-02-26 02:24:42 UTC (rev 1043) +++ sqlalchemy/trunk/lib/sqlalchemy/sql.py 2006-02-26 02:25:42 UTC (rev 1044) </span><span class="lines">@@ -616,6 +616,8 @@ </span><span class="cx"> visitor.visit_bindparam(self) </span><span class="cx"> def _get_from_objects(self): </span><span class="cx"> return [] </span><ins>+ def copy_container(self): + return BindParamClause(self.key, self.value, self.shortname, self.type) </ins><span class="cx"> def typeprocess(self, value, engine): </span><span class="cx"> return self._get_convert_type(engine).convert_bind_param(value, engine) </span><span class="cx"> def compare(self, other): </span></span></pre></div> <a id="sqlalchemytrunktestmanytomanypy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/test/manytomany.py (1043 => 1044)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/test/manytomany.py 2006-02-26 02:24:42 UTC (rev 1043) +++ sqlalchemy/trunk/test/manytomany.py 2006-02-26 02:25:42 UTC (rev 1044) </span><span class="lines">@@ -206,8 +206,67 @@ </span><span class="cx"> del s.courses[1] </span><span class="cx"> self.assert_(len(s.courses) == 2) </span><span class="cx"> </span><del>- </del><ins>+class M2MTest3(testbase.AssertMixin): + def setUpAll(self): + e = testbase.db + global c, c2a1, c2a2, b, a + c = Table('c', e, + Column('c1', Integer, primary_key = True), + Column('c2', String(20)), + ).create() </ins><span class="cx"> </span><ins>+ a = Table('a', e, + Column('a1', Integer, primary_key=True), + Column('a2', String(20)), + Column('c1', Integer, ForeignKey('c.c1')) + ).create() + + c2a1 = Table('ctoaone', e, + Column('c1', Integer, ForeignKey('c.c1')), + Column('a1', Integer, ForeignKey('a.a1')) + ).create() + c2a2 = Table('ctoatwo', e, + Column('c1', Integer, ForeignKey('c.c1')), + Column('a1', Integer, ForeignKey('a.a1')) + ).create() + + b = Table('b', e, + Column('b1', Integer, primary_key=True), + Column('a1', Integer, ForeignKey('a.a1')), + Column('b2', Boolean) + ).create() + + def tearDownAll(self): + b.drop() + c2a2.drop() + c2a1.drop() + a.drop() + c.drop() + + def testbasic(self): + class C(object):pass + class A(object):pass + class B(object):pass + + assign_mapper(B, b) + + assign_mapper(A, a, + properties = { + 'tbs' : relation(B, primaryjoin=and_(b.c.a1==a.c.a1, b.c.b2 == True), lazy=False), + } + ) + + assign_mapper(C, c, + properties = { + 'a1s' : relation(A, secondary=c2a1, lazy=False), + 'a2s' : relation(A, secondary=c2a2, lazy=False) + } + ) + + o1 = C.get(1) + + + </ins><span class="cx"> if __name__ == "__main__": </span><span class="cx"> testbase.main() </span><span class="cx"> </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-02-26 02:24:53
|
<!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>[1043] sqlalchemy/trunk/lib/sqlalchemy: create() statements return the created object so they can be instantiated and </title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1043</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-02-25 20:24:42 -0600 (Sat, 25 Feb 2006)</dd> </dl> <h3>Log Message</h3> <pre>create() statements return the created object so they can be instantiated and create()'ed in one line</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunklibsqlalchemyenginepy">sqlalchemy/trunk/lib/sqlalchemy/engine.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemyschemapy">sqlalchemy/trunk/lib/sqlalchemy/schema.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunklibsqlalchemyenginepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/engine.py (1042 => 1043)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/engine.py 2006-02-26 00:04:43 UTC (rev 1042) +++ sqlalchemy/trunk/lib/sqlalchemy/engine.py 2006-02-26 02:24:42 UTC (rev 1043) </span><span class="lines">@@ -296,6 +296,7 @@ </span><span class="cx"> def create(self, entity, **params): </span><span class="cx"> """creates a table or index within this engine's database connection given a schema.Table object.""" </span><span class="cx"> entity.accept_schema_visitor(self.schemagenerator(**params)) </span><ins>+ return entity </ins><span class="cx"> </span><span class="cx"> def drop(self, entity, **params): </span><span class="cx"> """drops a table or index within this engine's database connection given a schema.Table object.""" </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemyschemapy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/schema.py (1042 => 1043)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/schema.py 2006-02-26 00:04:43 UTC (rev 1042) +++ sqlalchemy/trunk/lib/sqlalchemy/schema.py 2006-02-26 02:24:42 UTC (rev 1043) </span><span class="lines">@@ -177,6 +177,7 @@ </span><span class="cx"> del self.engine.tables[key] </span><span class="cx"> def create(self, **params): </span><span class="cx"> self.engine.create(self) </span><ins>+ return self </ins><span class="cx"> def drop(self, **params): </span><span class="cx"> self.engine.drop(self) </span><span class="cx"> def toengine(self, engine, schema=None): </span><span class="lines">@@ -462,6 +463,7 @@ </span><span class="cx"> self.table)) </span><span class="cx"> def create(self): </span><span class="cx"> self.engine.create(self) </span><ins>+ return self </ins><span class="cx"> def drop(self): </span><span class="cx"> self.engine.drop(self) </span><span class="cx"> def execute(self): </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-02-26 00:04:57
|
<!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>[1042] sqlalchemy/trunk/doc/build/content/datamapping.myt: fixed many-to-many example, which was utterly incorrect in many ways</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1042</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-02-25 18:04:43 -0600 (Sat, 25 Feb 2006)</dd> </dl> <h3>Log Message</h3> <pre>fixed many-to-many example, which was utterly incorrect in many ways</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunkdocbuildcontentdatamappingmyt">sqlalchemy/trunk/doc/build/content/datamapping.myt</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunkdocbuildcontentdatamappingmyt"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/doc/build/content/datamapping.myt (1041 => 1042)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/doc/build/content/datamapping.myt 2006-02-25 17:50:46 UTC (rev 1041) +++ sqlalchemy/trunk/doc/build/content/datamapping.myt 2006-02-26 00:04:43 UTC (rev 1042) </span><span class="lines">@@ -619,7 +619,7 @@ </span><span class="cx"> </span><span class="cx"> keywords = Table('keywords', engine, </span><span class="cx"> Column('keyword_id', Integer, primary_key = True), </span><del>- Column('name', String(50)) </del><ins>+ Column('keyword_name', String(50)) </ins><span class="cx"> ) </span><span class="cx"> </span><span class="cx"> itemkeywords = Table('article_keywords', engine, </span><span class="lines">@@ -630,7 +630,7 @@ </span><span class="cx"> # class definitions </span><span class="cx"> class Keyword(object): </span><span class="cx"> def __init__(self, name = None): </span><del>- self.name = name </del><ins>+ self.keyword_name = name </ins><span class="cx"> </span><span class="cx"> class Article(object): </span><span class="cx"> pass </span><span class="lines">@@ -638,7 +638,7 @@ </span><span class="cx"> # define a mapper that does many-to-many on the 'itemkeywords' association </span><span class="cx"> # table </span><span class="cx"> Article.mapper = mapper(Article, articles, properties = dict( </span><del>- keywords = relation(mapper(Keyword, keywords), keywords, itemkeywords, lazy=False) </del><ins>+ keywords = relation(mapper(Keyword, keywords), itemkeywords, lazy=False) </ins><span class="cx"> ) </span><span class="cx"> ) </span><span class="cx"> </span><span class="lines">@@ -666,7 +666,7 @@ </span><span class="cx"> [{'keyword_id': 1, 'article_id': 1}, {'keyword_id': 2, 'article_id': 1}] </span><span class="cx"> </&> </span><span class="cx"> # select articles based on a keyword. select_by will handle the extra joins. </span><del>- <&formatting.myt:poplink&>articles = Article.mapper.select_by(keyword='politics') </del><ins>+ <&formatting.myt:poplink&>articles = Article.mapper.select_by(keyword_name='politics') </ins><span class="cx"> <&|formatting.myt:codepopper, link="sql" &> </span><span class="cx"> SELECT articles.article_id AS articles_article_id, </span><span class="cx"> articles.article_headline AS articles_article_headline, </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-02-25 17:50:57
|
<!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>[1041] sqlalchemy/trunk/lib/sqlalchemy/ext/proxy.py: Refactored ProxyEngine into BaseProxyEngine and ProxyEngine.</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1041</dd> <dt>Author</dt> <dd>jeff</dd> <dt>Date</dt> <dd>2006-02-25 11:50:46 -0600 (Sat, 25 Feb 2006)</dd> </dl> <h3>Log Message</h3> <pre>Refactored ProxyEngine into BaseProxyEngine and ProxyEngine. Also added an AutoConnectProxyEngine to late bind to a particular dburi. I ran the proxy_engine test, however, I don't have postgresql installed so not all tests worked. Also, I don't have an WSGI package installed to run the wsgi tests.</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunklibsqlalchemyextproxypy">sqlalchemy/trunk/lib/sqlalchemy/ext/proxy.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunklibsqlalchemyextproxypy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/ext/proxy.py (1040 => 1041)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/ext/proxy.py 2006-02-25 07:22:01 UTC (rev 1040) +++ sqlalchemy/trunk/lib/sqlalchemy/ext/proxy.py 2006-02-25 17:50:46 UTC (rev 1041) </span><span class="lines">@@ -9,7 +9,72 @@ </span><span class="cx"> </span><span class="cx"> import thread, weakref </span><span class="cx"> </span><del>-class ProxyEngine(object): </del><ins>+class BaseProxyEngine(object): + ''' + Basis for all proxy engines + ''' + def __init__(self): + self.tables = {} + + def get_engine(self): + raise NotImplementedError + + def set_engine(self, engine): + raise NotImplementedError + + engine = property(get_engine, set_engine) + + def hash_key(self): + return "%s(%s)" % (self.__class__.__name__, id(self)) + + def oid_column_name(self): + # NOTE: setting up mappers fails unless the proxy engine returns + # something for oid column name, and the call happens too early + # to proxy, so effecticely no oids are allowed when using + # proxy engine + e= self.get_engine() + if e is None: + return None + return e.oid_column_name() + + def type_descriptor(self, typeobj): + """Proxy point: return a ProxyTypeEngine + """ + return ProxyTypeEngine(self, typeobj) + + def __getattr__(self, attr): + # call get_engine() to give subclasses a chance to change + # connection establishment behavior + e= self.get_engine() + if e is not None: + return getattr(e, attr) + raise AttributeError('No connection established in ProxyEngine: ' + ' no access to %s' % attr) + +class AutoConnectEngine(BaseProxyEngine): + ''' + An SQLEngine proxy that automatically connects when necessary. + ''' + + def __init__(self, dburi, opts=None, **kwargs): + BaseProxyEngine.__init__(self) + self.dburi= dburi + self.opts= opts + self.kwargs= kwargs + self._engine= None + + def get_engine(self): + if self._engine is None: + self._engine= create_engine( self.dburi, self.opts, **self.kwargs ) + return self._engine + + def set_engine(self, engine): + raise NotImplementedError + + engine = property(get_engine, set_engine) + + +class ProxyEngine(BaseProxyEngine): </ins><span class="cx"> """ </span><span class="cx"> SQLEngine proxy. Supports lazy and late initialization by </span><span class="cx"> delegating to a real engine (set with connect()), and using proxy </span><span class="lines">@@ -17,11 +82,11 @@ </span><span class="cx"> """ </span><span class="cx"> </span><span class="cx"> def __init__(self): </span><ins>+ BaseProxyEngine.__init__(self) </ins><span class="cx"> # create the local storage for uri->engine map and current engine </span><span class="cx"> self.storage = local() </span><span class="cx"> self.storage.connection = {} </span><span class="cx"> self.storage.engine = None </span><del>- self.tables = {} </del><span class="cx"> </span><span class="cx"> def connect(self, uri, opts=None, **kwargs): </span><span class="cx"> """Establish connection to a real engine. </span><span class="lines">@@ -49,32 +114,7 @@ </span><span class="cx"> </span><span class="cx"> engine = property(get_engine, set_engine) </span><span class="cx"> </span><del>- def hash_key(self): - return "%s(%s)" % (self.__class__.__name__, id(self)) </del><span class="cx"> </span><del>- def oid_column_name(self): - # NOTE: setting up mappers fails unless the proxy engine returns - # something for oid column name, and the call happens too early - # to proxy, so effecticely no oids are allowed when using - # proxy engine - if self.storage.engine is None: - return None - return self.get_engine().oid_column_name() - - - def type_descriptor(self, typeobj): - """Proxy point: return a ProxyTypeEngine - """ - return ProxyTypeEngine(self, typeobj) - - def __getattr__(self, attr): - # call get_engine() to give subclasses a chance to change - # connection establishment behavior - if self.get_engine() is not None: - return getattr(self.engine, attr) - raise AttributeError('No connection established in ProxyEngine: ' - ' no access to %s' % attr) - </del><span class="cx"> class ProxyType(object): </span><span class="cx"> """ProxyType base class; used by ProxyTypeEngine to construct proxying </span><span class="cx"> types </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-02-25 07:22:10
|
<!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>[1040] sqlalchemy/trunk/test: clauseelement.compile() totally works without an engine</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1040</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-02-25 01:22:01 -0600 (Sat, 25 Feb 2006)</dd> </dl> <h3>Log Message</h3> <pre>clauseelement.compile() totally works without an engine</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunklibsqlalchemysqlpy">sqlalchemy/trunk/lib/sqlalchemy/sql.py</a></li> <li><a href="#sqlalchemytrunktestselectpy">sqlalchemy/trunk/test/select.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunklibsqlalchemysqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/sql.py (1039 => 1040)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/sql.py 2006-02-25 07:12:50 UTC (rev 1039) +++ sqlalchemy/trunk/lib/sqlalchemy/sql.py 2006-02-25 07:22:01 UTC (rev 1040) </span><span class="lines">@@ -1275,6 +1275,8 @@ </span><span class="cx"> if self._engine is not None: </span><span class="cx"> return self._engine </span><span class="cx"> for f in self._froms.values(): </span><ins>+ if f is self: + continue </ins><span class="cx"> e = f.engine </span><span class="cx"> if e is not None: </span><span class="cx"> self._engine = e </span></span></pre></div> <a id="sqlalchemytrunktestselectpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/test/select.py (1039 => 1040)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/test/select.py 2006-02-25 07:12:50 UTC (rev 1039) +++ sqlalchemy/trunk/test/select.py 2006-02-25 07:22:01 UTC (rev 1040) </span><span class="lines">@@ -57,9 +57,7 @@ </span><span class="cx"> </span><span class="cx"> class SQLTest(PersistTest): </span><span class="cx"> def runtest(self, clause, result, engine = None, params = None, checkparams = None): </span><del>- if engine is None: - engine = db - c = clause.compile(engine, params) </del><ins>+ c = clause.compile(parameters = params, engine=engine) </ins><span class="cx"> self.echo("\nSQL String:\n" + str(c) + repr(c.get_params())) </span><span class="cx"> cc = re.sub(r'\n', '', str(c)) </span><span class="cx"> self.assert_(cc == result, str(c) + "\n does not match \n" + result) </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-02-25 07:13:04
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head><style type="text/css"><!-- #msg dl { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; } #msg dt { float: left; width: 6em; font-weight: bold; } #msg dt:after { content:':';} #msg dl, #msg dt, #msg ul, #msg li { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; } #msg dl a { font-weight: bold} #msg dl a:link { color:#fc3; } #msg dl a:active { color:#ff0; } #msg dl a:visited { color:#cc6; } h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; } #msg pre { overflow: auto; background: #ffc; border: 1px #fc0 solid; padding: 6px; } #msg ul, pre { overflow: auto; } #patch { width: 100%; } #patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;} #patch .propset h4, #patch .binary h4 {margin:0;} #patch pre {padding:0;line-height:1.2em;margin:0;} #patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;} #patch .propset .diff, #patch .binary .diff {padding:10px 0;} #patch span {display:block;padding:0 10px;} #patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;} #patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;} #patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;} #patch .lines, .info {color:#888;background:#fff;} --></style> <title>[1039] sqlalchemy/trunk: merged sql_rearrangement branch , refactors sql package to work standalone with </title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1039</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-02-25 01:12:50 -0600 (Sat, 25 Feb 2006)</dd> </dl> <h3>Log Message</h3> <pre>merged sql_rearrangement branch , refactors sql package to work standalone with clause elements including tables and columns, schema package deals with "physical" representations</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunkCHANGES">sqlalchemy/trunk/CHANGES</a></li> <li><a href="#sqlalchemytrunklibsqlalchemy__init__py">sqlalchemy/trunk/lib/sqlalchemy/__init__.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemyansisqlpy">sqlalchemy/trunk/lib/sqlalchemy/ansisql.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemydatabasesmysqlpy">sqlalchemy/trunk/lib/sqlalchemy/databases/mysql.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemydatabasespostgrespy">sqlalchemy/trunk/lib/sqlalchemy/databases/postgres.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemyenginepy">sqlalchemy/trunk/lib/sqlalchemy/engine.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemyextproxypy">sqlalchemy/trunk/lib/sqlalchemy/ext/proxy.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemymappingmapperpy">sqlalchemy/trunk/lib/sqlalchemy/mapping/mapper.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemymappingobjectstorepy">sqlalchemy/trunk/lib/sqlalchemy/mapping/objectstore.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemyschemapy">sqlalchemy/trunk/lib/sqlalchemy/schema.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemysqlpy">sqlalchemy/trunk/lib/sqlalchemy/sql.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemyutilpy">sqlalchemy/trunk/lib/sqlalchemy/util.py</a></li> <li><a href="#sqlalchemytrunktestobjectstorepy">sqlalchemy/trunk/test/objectstore.py</a></li> <li><a href="#sqlalchemytrunktestselectpy">sqlalchemy/trunk/test/select.py</a></li> <li><a href="#sqlalchemytrunktesttestbasepy">sqlalchemy/trunk/test/testbase.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunkCHANGES"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/CHANGES (1038 => 1039)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/CHANGES 2006-02-25 07:06:09 UTC (rev 1038) +++ sqlalchemy/trunk/CHANGES 2006-02-25 07:12:50 UTC (rev 1039) </span><span class="lines">@@ -2,6 +2,9 @@ </span><span class="cx"> - fix to Oracle "row_number over" clause with mulitple tables </span><span class="cx"> - mapper.get() was not selecting multiple-keyed objects if the mapper's table was a join, </span><span class="cx"> such as in an inheritance relationship, this is fixed. </span><ins>+- overhaul to sql/schema packages so that the sql package can run all on its own, +producing selects, inserts, etc. without any engine dependencies. Table/Column +are the "physical" subclasses of TableClause/ColumnClause. </ins><span class="cx"> 0.1.2 </span><span class="cx"> - fixed a recursive call in schema that was somehow running 994 times then returning </span><span class="cx"> normally. broke nothing, slowed down everything. thanks to jpellerin for finding this. </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemy__init__py"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/__init__.py (1038 => 1039)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/__init__.py 2006-02-25 07:06:09 UTC (rev 1038) +++ sqlalchemy/trunk/lib/sqlalchemy/__init__.py 2006-02-25 07:12:50 UTC (rev 1039) </span><span class="lines">@@ -6,8 +6,8 @@ </span><span class="cx"> </span><span class="cx"> from engine import * </span><span class="cx"> from types import * </span><ins>+from sql import * </ins><span class="cx"> from schema import * </span><span class="cx"> from exceptions import * </span><del>-from sql import * </del><span class="cx"> import mapping as mapperlib </span><span class="cx"> from mapping import * </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemyansisqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/ansisql.py (1038 => 1039)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/ansisql.py 2006-02-25 07:06:09 UTC (rev 1038) +++ sqlalchemy/trunk/lib/sqlalchemy/ansisql.py 2006-02-25 07:12:50 UTC (rev 1039) </span><span class="lines">@@ -152,16 +152,11 @@ </span><span class="cx"> # if we are within a visit to a Select, set up the "typemap" </span><span class="cx"> # for this column which is used to translate result set values </span><span class="cx"> self.typemap.setdefault(column.key.lower(), column.type) </span><del>- if column.table.name is None: </del><ins>+ if column.table is not None and column.table.name is None: </ins><span class="cx"> self.strings[column] = column.name </span><span class="cx"> else: </span><span class="cx"> self.strings[column] = "%s.%s" % (column.table.name, column.name) </span><span class="cx"> </span><del>- def visit_columnclause(self, column): - if column.table is not None and column.table.name is not None: - self.strings[column] = "%s.%s" % (column.table.name, column.text) - else: - self.strings[column] = column.text </del><span class="cx"> </span><span class="cx"> def visit_fromclause(self, fromclause): </span><span class="cx"> self.froms[fromclause] = fromclause.from_name </span><span class="lines">@@ -257,11 +252,13 @@ </span><span class="cx"> l = co.label(co._label) </span><span class="cx"> l.accept_visitor(self) </span><span class="cx"> inner_columns[co._label] = l </span><del>- elif select.issubquery and isinstance(co, Column): </del><ins>+ # TODO: figure this out, a ColumnClause with a select as a parent + # is different from any other kind of parent + elif select.issubquery and isinstance(co, sql.ColumnClause) and co.table is not None and not isinstance(co.table, sql.Select): </ins><span class="cx"> # SQLite doesnt like selecting from a subquery where the column </span><span class="cx"> # names look like table.colname, so add a label synonomous with </span><span class="cx"> # the column name </span><del>- l = co.label(co.key) </del><ins>+ l = co.label(co.text) </ins><span class="cx"> l.accept_visitor(self) </span><span class="cx"> inner_columns[self.get_str(l.obj)] = l </span><span class="cx"> else: </span><span class="lines">@@ -379,7 +376,7 @@ </span><span class="cx"> contains a Sequence object.""" </span><span class="cx"> pass </span><span class="cx"> </span><del>- def visit_insert_column(selef, column): </del><ins>+ def visit_insert_column(self, column): </ins><span class="cx"> """called when visiting an Insert statement, for each column in the table </span><span class="cx"> that is a NULL insert into the table""" </span><span class="cx"> pass </span><span class="lines">@@ -395,8 +392,8 @@ </span><span class="cx"> self.visit_insert_sequence(c, seq) </span><span class="cx"> vis = DefaultVisitor() </span><span class="cx"> for c in insert_stmt.table.c: </span><del>- if (self.parameters is None or self.parameters.get(c.key, None) is None): - c.accept_visitor(vis) </del><ins>+ if (isinstance(c, schema.SchemaItem) and (self.parameters is None or self.parameters.get(c.key, None) is None)): + c.accept_schema_visitor(vis) </ins><span class="cx"> </span><span class="cx"> self.isinsert = True </span><span class="cx"> colparams = self._get_colparams(insert_stmt) </span><span class="lines">@@ -419,7 +416,7 @@ </span><span class="cx"> return self.bindparam_string(p.key) </span><span class="cx"> else: </span><span class="cx"> p.accept_visitor(self) </span><del>- if isinstance(p, sql.ClauseElement): </del><ins>+ if isinstance(p, sql.ClauseElement) and not isinstance(p, sql.ColumnClause): </ins><span class="cx"> return "(" + self.get_str(p) + ")" </span><span class="cx"> else: </span><span class="cx"> return self.get_str(p) </span><span class="lines">@@ -466,7 +463,7 @@ </span><span class="cx"> # now go thru compiled params, get the Column object for each key </span><span class="cx"> d = {} </span><span class="cx"> for key, value in parameters.iteritems(): </span><del>- if isinstance(key, schema.Column): </del><ins>+ if isinstance(key, sql.ColumnClause): </ins><span class="cx"> d[key] = value </span><span class="cx"> else: </span><span class="cx"> try: </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemydatabasesmysqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/databases/mysql.py (1038 => 1039)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/databases/mysql.py 2006-02-25 07:06:09 UTC (rev 1038) +++ sqlalchemy/trunk/lib/sqlalchemy/databases/mysql.py 2006-02-25 07:12:50 UTC (rev 1039) </span><span class="lines">@@ -131,11 +131,6 @@ </span><span class="cx"> def supports_sane_rowcount(self): </span><span class="cx"> return False </span><span class="cx"> </span><del>- def tableimpl(self, table, **kwargs): - """returns a new sql.TableImpl object to correspond to the given Table object.""" - mysql_engine = kwargs.pop('mysql_engine', None) - return MySQLTableImpl(table, mysql_engine=mysql_engine) - </del><span class="cx"> def compiler(self, statement, bindparams, **kwargs): </span><span class="cx"> return MySQLCompiler(self, statement, bindparams, **kwargs) </span><span class="cx"> </span><span class="lines">@@ -175,7 +170,7 @@ </span><span class="cx"> #ischema.reflecttable(self, table, ischema_names, use_mysql=True) </span><span class="cx"> </span><span class="cx"> tabletype, foreignkeyD = self.moretableinfo(table=table) </span><del>- table._impl.mysql_engine = tabletype </del><ins>+ table.kwargs['mysql_engine'] = tabletype </ins><span class="cx"> </span><span class="cx"> c = self.execute("describe " + table.name, {}) </span><span class="cx"> while True: </span><span class="lines">@@ -235,14 +230,6 @@ </span><span class="cx"> return (tabletype, foreignkeyD) </span><span class="cx"> </span><span class="cx"> </span><del>-class MySQLTableImpl(sql.TableImpl): - """attached to a schema.Table to provide it with a Selectable interface - as well as other functions - """ - def __init__(self, table, mysql_engine=None): - super(MySQLTableImpl, self).__init__(table) - self.mysql_engine = mysql_engine - </del><span class="cx"> class MySQLCompiler(ansisql.ANSICompiler): </span><span class="cx"> </span><span class="cx"> def visit_function(self, func): </span><span class="lines">@@ -277,12 +264,13 @@ </span><span class="cx"> if first_pk and isinstance(column.type, types.Integer): </span><span class="cx"> colspec += " AUTO_INCREMENT" </span><span class="cx"> if column.foreign_key: </span><del>- colspec += ", FOREIGN KEY (%s) REFERENCES %s(%s)" % (column.name, column.column.foreign_key.column.table.name, column.column.foreign_key.column.name) </del><ins>+ colspec += ", FOREIGN KEY (%s) REFERENCES %s(%s)" % (column.name, column.foreign_key.column.table.name, column.foreign_key.column.name) </ins><span class="cx"> return colspec </span><span class="cx"> </span><span class="cx"> def post_create_table(self, table): </span><del>- if table.mysql_engine is not None: - return " ENGINE=%s" % table.mysql_engine </del><ins>+ mysql_engine = table.kwargs.get('mysql_engine', None) + if mysql_engine is not None: + return " ENGINE=%s" % mysql_engine </ins><span class="cx"> else: </span><span class="cx"> return "" </span><span class="cx"> </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemydatabasespostgrespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/databases/postgres.py (1038 => 1039)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/databases/postgres.py 2006-02-25 07:06:09 UTC (rev 1038) +++ sqlalchemy/trunk/lib/sqlalchemy/databases/postgres.py 2006-02-25 07:12:50 UTC (rev 1039) </span><span class="lines">@@ -312,7 +312,7 @@ </span><span class="cx"> if column.primary_key and not override_pk: </span><span class="cx"> colspec += " PRIMARY KEY" </span><span class="cx"> if column.foreign_key: </span><del>- colspec += " REFERENCES %s(%s)" % (column.column.foreign_key.column.table.fullname, column.column.foreign_key.column.name) </del><ins>+ colspec += " REFERENCES %s(%s)" % (column.foreign_key.column.table.fullname, column.foreign_key.column.name) </ins><span class="cx"> return colspec </span><span class="cx"> </span><span class="cx"> def visit_sequence(self, sequence): </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemyenginepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/engine.py (1038 => 1039)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/engine.py 2006-02-25 07:06:09 UTC (rev 1038) +++ sqlalchemy/trunk/lib/sqlalchemy/engine.py 2006-02-25 07:12:50 UTC (rev 1039) </span><span class="lines">@@ -16,8 +16,7 @@ </span><span class="cx"> of DBAPI, and is the central switching point for abstracting different kinds of database </span><span class="cx"> behavior into a consistent set of behaviors. It provides a variety of factory methods </span><span class="cx"> to produce everything specific to a certain kind of database, including a Compiler, </span><del>-schema creation/dropping objects, and TableImpl and ColumnImpl objects to augment the -behavior of table metadata objects. </del><ins>+schema creation/dropping objects. </ins><span class="cx"> </span><span class="cx"> The term "database-specific" will be used to describe any object or function that has behavior </span><span class="cx"> corresponding to a particular vendor, such as mysql-specific, sqlite-specific, etc. </span><span class="lines">@@ -131,7 +130,7 @@ </span><span class="cx"> </span><span class="cx"> def get_column_default(self, column): </span><span class="cx"> if column.default is not None: </span><del>- return column.default.accept_visitor(self) </del><ins>+ return column.default.accept_schema_visitor(self) </ins><span class="cx"> else: </span><span class="cx"> return None </span><span class="cx"> </span><span class="lines">@@ -296,11 +295,11 @@ </span><span class="cx"> </span><span class="cx"> def create(self, entity, **params): </span><span class="cx"> """creates a table or index within this engine's database connection given a schema.Table object.""" </span><del>- entity.accept_visitor(self.schemagenerator(**params)) </del><ins>+ entity.accept_schema_visitor(self.schemagenerator(**params)) </ins><span class="cx"> </span><span class="cx"> def drop(self, entity, **params): </span><span class="cx"> """drops a table or index within this engine's database connection given a schema.Table object.""" </span><del>- entity.accept_visitor(self.schemadropper(**params)) </del><ins>+ entity.accept_schema_visitor(self.schemadropper(**params)) </ins><span class="cx"> </span><span class="cx"> def compile(self, statement, parameters, **kwargs): </span><span class="cx"> """given a sql.ClauseElement statement plus optional bind parameters, creates a new </span><span class="lines">@@ -315,28 +314,6 @@ </span><span class="cx"> """given a Table object, reflects its columns and properties from the database.""" </span><span class="cx"> raise NotImplementedError() </span><span class="cx"> </span><del>- def tableimpl(self, table, **kwargs): - """returns a new sql.TableImpl object to correspond to the given Table object. - A TableImpl provides SQL statement builder operations on a Table metadata object, - and a subclass of this object may be provided by a SQLEngine subclass to provide - database-specific behavior.""" - return sql.TableImpl(table) - - def columnimpl(self, column): - """returns a new sql.ColumnImpl object to correspond to the given Column object. - A ColumnImpl provides SQL statement builder operations on a Column metadata object, - and a subclass of this object may be provided by a SQLEngine subclass to provide - database-specific behavior.""" - return sql.ColumnImpl(column) - - def indeximpl(self, index): - """returns a new sql.IndexImpl object to correspond to the given Index - object. An IndexImpl provides SQL statement builder operations on an - Index metadata object, and a subclass of this object may be provided - by a SQLEngine subclass to provide database-specific behavior. - """ - return sql.IndexImpl(index) - </del><span class="cx"> def get_default_schema_name(self): </span><span class="cx"> """returns the currently selected schema in the current connection.""" </span><span class="cx"> return None </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemyextproxypy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/ext/proxy.py (1038 => 1039)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/ext/proxy.py 2006-02-25 07:06:09 UTC (rev 1038) +++ sqlalchemy/trunk/lib/sqlalchemy/ext/proxy.py 2006-02-25 07:12:50 UTC (rev 1039) </span><span class="lines">@@ -13,7 +13,7 @@ </span><span class="cx"> """ </span><span class="cx"> SQLEngine proxy. Supports lazy and late initialization by </span><span class="cx"> delegating to a real engine (set with connect()), and using proxy </span><del>- classes for TableImpl, ColumnImpl and TypeEngine. </del><ins>+ classes for TypeEngine. </ins><span class="cx"> """ </span><span class="cx"> </span><span class="cx"> def __init__(self): </span><span class="lines">@@ -61,15 +61,6 @@ </span><span class="cx"> return None </span><span class="cx"> return self.get_engine().oid_column_name() </span><span class="cx"> </span><del>- def columnimpl(self, column): - """Proxy point: return a ProxyColumnImpl - """ - return ProxyColumnImpl(self, column) - - def tableimpl(self, table): - """Proxy point: return a ProxyTableImpl - """ - return ProxyTableImpl(self, table) </del><span class="cx"> </span><span class="cx"> def type_descriptor(self, typeobj): </span><span class="cx"> """Proxy point: return a ProxyTypeEngine </span><span class="lines">@@ -84,45 +75,6 @@ </span><span class="cx"> raise AttributeError('No connection established in ProxyEngine: ' </span><span class="cx"> ' no access to %s' % attr) </span><span class="cx"> </span><del>- -class ProxyColumnImpl(sql.ColumnImpl): - """Proxy column; defers engine access to ProxyEngine - """ - def __init__(self, engine, column): - sql.ColumnImpl.__init__(self, column) - self._engine = engine - self.impls = weakref.WeakKeyDictionary() - def _get_impl(self): - e = self._engine.engine - try: - return self.impls[e] - except KeyError: - impl = e.columnimpl(self.column) - self.impls[e] = impl - def __getattr__(self, key): - return getattr(self._get_impl(), key) - engine = property(lambda self: self._engine.engine) - -class ProxyTableImpl(sql.TableImpl): - """Proxy table; defers engine access to ProxyEngine - """ - def __init__(self, engine, table): - sql.TableImpl.__init__(self, table) - self._engine = engine - self.impls = weakref.WeakKeyDictionary() - def _get_impl(self): - e = self._engine.engine - try: - return self.impls[e] - except KeyError: - impl = e.tableimpl(self.table) - self.impls[e] = impl - return impl - def __getattr__(self, key): - return getattr(self._get_impl(), key) - - engine = property(lambda self: self._engine.engine) - </del><span class="cx"> class ProxyType(object): </span><span class="cx"> """ProxyType base class; used by ProxyTypeEngine to construct proxying </span><span class="cx"> types </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemymappingmapperpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/mapping/mapper.py (1038 => 1039)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/mapping/mapper.py 2006-02-25 07:06:09 UTC (rev 1038) +++ sqlalchemy/trunk/lib/sqlalchemy/mapping/mapper.py 2006-02-25 07:12:50 UTC (rev 1039) </span><span class="lines">@@ -262,7 +262,7 @@ </span><span class="cx"> """returns an instance of the object based on the given identifier, or None </span><span class="cx"> if not found. The *ident argument is a </span><span class="cx"> list of primary key columns in the order of the table def's primary key columns.""" </span><del>- key = objectstore.get_id_key(ident, self.class_, self.primarytable) </del><ins>+ key = objectstore.get_id_key(ident, self.class_) </ins><span class="cx"> #print "key: " + repr(key) + " ident: " + repr(ident) </span><span class="cx"> return self._get(key, ident) </span><span class="cx"> </span><span class="lines">@@ -284,7 +284,7 @@ </span><span class="cx"> </span><span class="cx"> </span><span class="cx"> def identity_key(self, *primary_key): </span><del>- return objectstore.get_id_key(tuple(primary_key), self.class_, self.primarytable) </del><ins>+ return objectstore.get_id_key(tuple(primary_key), self.class_) </ins><span class="cx"> </span><span class="cx"> def instance_key(self, instance): </span><span class="cx"> return self.identity_key(*[self._getattrbycolumn(instance, column) for column in self.pks_by_table[self.table]]) </span><span class="lines">@@ -683,7 +683,7 @@ </span><span class="cx"> return statement </span><span class="cx"> </span><span class="cx"> def _identity_key(self, row): </span><del>- return objectstore.get_row_key(row, self.class_, self.identitytable, self.pks_by_table[self.table]) </del><ins>+ return objectstore.get_row_key(row, self.class_, self.pks_by_table[self.table]) </ins><span class="cx"> </span><span class="cx"> def _instance(self, row, imap, result = None, populate_existing = False): </span><span class="cx"> """pulls an object instance from the given row and appends it to the given result </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemymappingobjectstorepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/mapping/objectstore.py (1038 => 1039)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/mapping/objectstore.py 2006-02-25 07:06:09 UTC (rev 1038) +++ sqlalchemy/trunk/lib/sqlalchemy/mapping/objectstore.py 2006-02-25 07:12:50 UTC (rev 1039) </span><span class="lines">@@ -48,7 +48,7 @@ </span><span class="cx"> self.hash_key = hash_key </span><span class="cx"> _sessions[self.hash_key] = self </span><span class="cx"> </span><del>- def get_id_key(ident, class_, table): </del><ins>+ def get_id_key(ident, class_): </ins><span class="cx"> """returns an identity-map key for use in storing/retrieving an item from the identity </span><span class="cx"> map, given a tuple of the object's primary key values. </span><span class="cx"> </span><span class="lines">@@ -62,10 +62,10 @@ </span><span class="cx"> selectable - a Selectable object which represents all the object's column-based fields. </span><span class="cx"> this Selectable may be synonymous with the table argument or can be a larger construct </span><span class="cx"> containing that table. return value: a tuple object which is used as an identity key. """ </span><del>- return (class_, table.hash_key(), tuple(ident)) </del><ins>+ return (class_, tuple(ident)) </ins><span class="cx"> get_id_key = staticmethod(get_id_key) </span><span class="cx"> </span><del>- def get_row_key(row, class_, table, primary_key): </del><ins>+ def get_row_key(row, class_, primary_key): </ins><span class="cx"> """returns an identity-map key for use in storing/retrieving an item from the identity </span><span class="cx"> map, given a result set row. </span><span class="cx"> </span><span class="lines">@@ -80,7 +80,7 @@ </span><span class="cx"> this Selectable may be synonymous with the table argument or can be a larger construct </span><span class="cx"> containing that table. return value: a tuple object which is used as an identity key. </span><span class="cx"> """ </span><del>- return (class_, table.hash_key(), tuple([row[column] for column in primary_key])) </del><ins>+ return (class_, tuple([row[column] for column in primary_key])) </ins><span class="cx"> get_row_key = staticmethod(get_row_key) </span><span class="cx"> </span><span class="cx"> class SessionTrans(object): </span><span class="lines">@@ -181,7 +181,6 @@ </span><span class="cx"> return None </span><span class="cx"> key = getattr(instance, '_instance_key', None) </span><span class="cx"> mapper = object_mapper(instance) </span><del>- key = (key[0], mapper.table.hash_key(), key[2]) </del><span class="cx"> u = self.uow </span><span class="cx"> if key is not None: </span><span class="cx"> if u.identity_map.has_key(key): </span><span class="lines">@@ -194,11 +193,11 @@ </span><span class="cx"> u.register_new(instance) </span><span class="cx"> return instance </span><span class="cx"> </span><del>-def get_id_key(ident, class_, table): - return Session.get_id_key(ident, class_, table) </del><ins>+def get_id_key(ident, class_): + return Session.get_id_key(ident, class_) </ins><span class="cx"> </span><del>-def get_row_key(row, class_, table, primary_key): - return Session.get_row_key(row, class_, table, primary_key) </del><ins>+def get_row_key(row, class_, primary_key): + return Session.get_row_key(row, class_, primary_key) </ins><span class="cx"> </span><span class="cx"> def begin(): </span><span class="cx"> """begins a new UnitOfWork transaction. the next commit will affect only </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemyschemapy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/schema.py (1038 => 1039)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/schema.py 2006-02-25 07:06:09 UTC (rev 1038) +++ sqlalchemy/trunk/lib/sqlalchemy/schema.py 2006-02-25 07:12:50 UTC (rev 1039) </span><span class="lines">@@ -14,7 +14,7 @@ </span><span class="cx"> the schema package "plugs in" to the SQL package. </span><span class="cx"> </span><span class="cx"> """ </span><del>- </del><ins>+import sql </ins><span class="cx"> from util import * </span><span class="cx"> from types import * </span><span class="cx"> from exceptions import * </span><span class="lines">@@ -29,30 +29,12 @@ </span><span class="cx"> for item in args: </span><span class="cx"> if item is not None: </span><span class="cx"> item._set_parent(self) </span><del>- - def accept_visitor(self, visitor): - """all schema items implement an accept_visitor method that should call the appropriate - visit_XXXX method upon the given visitor object.""" - raise NotImplementedError() - </del><span class="cx"> def _set_parent(self, parent): </span><span class="cx"> """a child item attaches itself to its parent via this method.""" </span><span class="cx"> raise NotImplementedError() </span><del>- - def hash_key(self): - """returns a string that identifies this SchemaItem uniquely""" - return "%s(%d)" % (self.__class__.__name__, id(self)) - </del><span class="cx"> def __repr__(self): </span><span class="cx"> return "%s()" % self.__class__.__name__ </span><span class="cx"> </span><del>- def __getattr__(self, key): - """proxies method calls to an underlying implementation object for methods not found - locally""" - if not self.__dict__.has_key('_impl'): - raise AttributeError(key) - return getattr(self._impl, key) - </del><span class="cx"> def _get_table_key(engine, name, schema): </span><span class="cx"> if schema is not None and schema == engine.get_default_schema_name(): </span><span class="cx"> schema = None </span><span class="lines">@@ -95,8 +77,10 @@ </span><span class="cx"> return table </span><span class="cx"> </span><span class="cx"> </span><del>-class Table(SchemaItem): - """represents a relational database table. </del><ins>+class Table(sql.TableClause, SchemaItem): + """represents a relational database table. This subclasses sql.TableClause to provide + a table that is "wired" to an engine. Whereas TableClause represents a table as its + used in a SQL expression, Table represents a table as its created in the database. </ins><span class="cx"> </span><span class="cx"> Be sure to look at sqlalchemy.sql.TableImpl for additional methods defined on a Table.""" </span><span class="cx"> __metaclass__ = TableSingleton </span><span class="lines">@@ -134,19 +118,15 @@ </span><span class="cx"> the same table twice will result in an exception. </span><span class="cx"> </span><span class="cx"> """ </span><del>- self.name = name - self.columns = OrderedProperties() - self.c = self.columns - self.foreign_keys = [] - self.primary_key = [] - self.engine = engine </del><ins>+ super(Table, self).__init__(name) + self._engine = engine </ins><span class="cx"> self.schema = kwargs.pop('schema', None) </span><del>- self._impl = self.engine.tableimpl(self, **kwargs) </del><span class="cx"> if self.schema is not None: </span><span class="cx"> self.fullname = "%s.%s" % (self.schema, self.name) </span><span class="cx"> else: </span><span class="cx"> self.fullname = self.name </span><del>- </del><ins>+ self.kwargs = kwargs + </ins><span class="cx"> def __repr__(self): </span><span class="cx"> return "Table(%s)" % string.join( </span><span class="cx"> [repr(self.name)] + [repr(self.engine)] + </span><span class="lines">@@ -160,44 +140,45 @@ </span><span class="cx"> else: </span><span class="cx"> return self.schema + "." + self.name </span><span class="cx"> </span><del>- def hash_key(self): - return "Table(%s)" % string.join( - [repr(self.name)] + [self.engine.hash_key()] + - ["%s=%s" % (k, repr(getattr(self, k))) for k in ['schema']], ',' - ) - </del><span class="cx"> def reload_values(self, *args): </span><span class="cx"> """clears out the columns and other properties of this Table, and reloads them from the </span><span class="cx"> given argument list. This is used with the "redefine" keyword argument sent to the </span><span class="cx"> metaclass constructor.""" </span><del>- self.columns = OrderedProperties() - self.c = self.columns - self.foreign_keys = [] - self.primary_key = [] - self._impl = self.engine.tableimpl(self) </del><ins>+ self._clear() + + print "RELOAD VALUES", args </ins><span class="cx"> self._init_items(*args) </span><span class="cx"> </span><span class="cx"> def append_item(self, item): </span><span class="cx"> """appends a Column item or other schema item to this Table.""" </span><span class="cx"> self._init_items(item) </span><del>- </del><ins>+ + def append_column(self, column): + if not column.hidden: + self._columns[column.key] = column + if column.primary_key: + self.primary_key.append(column) + column.table = self + column.type = self.engine.type_descriptor(column.type) + </ins><span class="cx"> def _set_parent(self, schema): </span><span class="cx"> schema.tables[self.name] = self </span><span class="cx"> self.schema = schema </span><del>- - def accept_visitor(self, visitor): </del><ins>+ def accept_schema_visitor(self, visitor): </ins><span class="cx"> """traverses the given visitor across the Column objects inside this Table, </span><span class="cx"> then calls the visit_table method on the visitor.""" </span><span class="cx"> for c in self.columns: </span><del>- c.accept_visitor(visitor) </del><ins>+ c.accept_schema_visitor(visitor) </ins><span class="cx"> return visitor.visit_table(self) </span><del>- </del><span class="cx"> def deregister(self): </span><span class="cx"> """removes this table from it's engines table registry. this does not </span><span class="cx"> issue a SQL DROP statement.""" </span><span class="cx"> key = _get_table_key(self.engine, self.name, self.schema) </span><span class="cx"> del self.engine.tables[key] </span><del>- </del><ins>+ def create(self, **params): + self.engine.create(self) + def drop(self, **params): + self.engine.drop(self) </ins><span class="cx"> def toengine(self, engine, schema=None): </span><span class="cx"> """returns a singleton instance of this Table with a different engine""" </span><span class="cx"> try: </span><span class="lines">@@ -211,8 +192,9 @@ </span><span class="cx"> args.append(c.copy()) </span><span class="cx"> return Table(self.name, engine, schema=schema, *args) </span><span class="cx"> </span><del>-class Column(SchemaItem): - """represents a column in a database table.""" </del><ins>+class Column(sql.ColumnClause, SchemaItem): + """represents a column in a database table. this is a subclass of sql.ColumnClause and + represents an actual existing table in the database, in a similar fashion as TableClause/Table.""" </ins><span class="cx"> def __init__(self, name, type, *args, **kwargs): </span><span class="cx"> """constructs a new Column object. Arguments are: </span><span class="cx"> </span><span class="lines">@@ -244,24 +226,27 @@ </span><span class="cx"> hidden=False : indicates this column should not be listed in the table's list of columns. Used for the "oid" </span><span class="cx"> column, which generally isnt in column lists. </span><span class="cx"> """ </span><del>- self.name = str(name) # in case of incoming unicode - self.type = type </del><ins>+ name = str(name) # in case of incoming unicode + super(Column, self).__init__(name, None, type) </ins><span class="cx"> self.args = args </span><span class="cx"> self.key = kwargs.pop('key', name) </span><del>- self.primary_key = kwargs.pop('primary_key', False) </del><ins>+ self._primary_key = kwargs.pop('primary_key', False) </ins><span class="cx"> self.nullable = kwargs.pop('nullable', not self.primary_key) </span><span class="cx"> self.hidden = kwargs.pop('hidden', False) </span><span class="cx"> self.default = kwargs.pop('default', None) </span><del>- self.foreign_key = None </del><ins>+ self._foreign_key = None </ins><span class="cx"> self._orig = None </span><span class="cx"> self._parent = None </span><span class="cx"> if len(kwargs): </span><span class="cx"> raise ArgumentError("Unknown arguments passed to Column: " + repr(kwargs.keys())) </span><del>- </del><ins>+ + primary_key = AttrProp('_primary_key') + foreign_key = AttrProp('_foreign_key') </ins><span class="cx"> original = property(lambda s: s._orig or s) </span><span class="cx"> parent = property(lambda s:s._parent or s) </span><span class="cx"> engine = property(lambda s: s.table.engine) </span><del>- </del><ins>+ columns = property(lambda self:[self]) + </ins><span class="cx"> def __repr__(self): </span><span class="cx"> return "Column(%s)" % string.join( </span><span class="cx"> [repr(self.name)] + [repr(self.type)] + </span><span class="lines">@@ -282,16 +267,7 @@ </span><span class="cx"> def _set_parent(self, table): </span><span class="cx"> if getattr(self, 'table', None) is not None: </span><span class="cx"> raise ArgumentError("this Column already has a table!") </span><del>- if not self.hidden: - table.columns[self.key] = self - if self.primary_key: - table.primary_key.append(self) - self.table = table - if self.table.engine is not None: - self.type = self.table.engine.type_descriptor(self.type) - - self._impl = self.table.engine.columnimpl(self) - </del><ins>+ table.append_column(self) </ins><span class="cx"> if self.default is not None: </span><span class="cx"> self.default = ColumnDefault(self.default) </span><span class="cx"> self._init_items(self.default) </span><span class="lines">@@ -320,35 +296,19 @@ </span><span class="cx"> selectable.columns[c.key] = c </span><span class="cx"> if self.primary_key: </span><span class="cx"> selectable.primary_key.append(c) </span><del>- c._impl = self.engine.columnimpl(c) </del><span class="cx"> if fk is not None: </span><span class="cx"> c._init_items(fk) </span><span class="cx"> return c </span><span class="cx"> </span><del>- def accept_visitor(self, visitor): </del><ins>+ def accept_schema_visitor(self, visitor): </ins><span class="cx"> """traverses the given visitor to this Column's default and foreign key object, </span><span class="cx"> then calls visit_column on the visitor.""" </span><span class="cx"> if self.default is not None: </span><del>- self.default.accept_visitor(visitor) </del><ins>+ self.default.accept_schema_visitor(visitor) </ins><span class="cx"> if self.foreign_key is not None: </span><del>- self.foreign_key.accept_visitor(visitor) </del><ins>+ self.foreign_key.accept_schema_visitor(visitor) </ins><span class="cx"> visitor.visit_column(self) </span><span class="cx"> </span><del>- def __lt__(self, other): return self._impl.__lt__(other) - def __le__(self, other): return self._impl.__le__(other) - def __eq__(self, other): return self._impl.__eq__(other) - def __ne__(self, other): return self._impl.__ne__(other) - def __gt__(self, other): return self._impl.__gt__(other) - def __ge__(self, other): return self._impl.__ge__(other) - def __add__(self, other): return self._impl.__add__(other) - def __sub__(self, other): return self._impl.__sub__(other) - def __mul__(self, other): return self._impl.__mul__(other) - def __and__(self, other): return self._impl.__and__(other) - def __or__(self, other): return self._impl.__or__(other) - def __div__(self, other): return self._impl.__div__(other) - def __truediv__(self, other): return self._impl.__truediv__(other) - def __invert__(self, other): return self._impl.__invert__(other) - def __str__(self): return self._impl.__str__() </del><span class="cx"> </span><span class="cx"> class ForeignKey(SchemaItem): </span><span class="cx"> """defines a ForeignKey constraint between two columns. ForeignKey is </span><span class="lines">@@ -374,7 +334,7 @@ </span><span class="cx"> elif self._colspec.table.schema is not None: </span><span class="cx"> return "%s.%s.%s" % (self._colspec.table.schema, self._colspec.table.name, self._colspec.column.key) </span><span class="cx"> else: </span><del>- return "%s.%s" % (self._colspec.table.name, self._colspec.column.key) </del><ins>+ return "%s.%s" % (self._colspec.table.name, self._colspec.key) </ins><span class="cx"> </span><span class="cx"> def references(self, table): </span><span class="cx"> """returns True if the given table is referenced by this ForeignKey.""" </span><span class="lines">@@ -406,7 +366,7 @@ </span><span class="cx"> </span><span class="cx"> column = property(lambda s: s._init_column()) </span><span class="cx"> </span><del>- def accept_visitor(self, visitor): </del><ins>+ def accept_schema_visitor(self, visitor): </ins><span class="cx"> """calls the visit_foreign_key method on the given visitor.""" </span><span class="cx"> visitor.visit_foreign_key(self) </span><span class="cx"> </span><span class="lines">@@ -432,7 +392,7 @@ </span><span class="cx"> """a default that takes effect on the database side""" </span><span class="cx"> def __init__(self, arg): </span><span class="cx"> self.arg = arg </span><del>- def accept_visitor(self, visitor): </del><ins>+ def accept_schema_visitor(self, visitor): </ins><span class="cx"> return visitor.visit_passive_default(self) </span><span class="cx"> def __repr__(self): </span><span class="cx"> return "PassiveDefault(%s)" % repr(self.arg) </span><span class="lines">@@ -442,7 +402,7 @@ </span><span class="cx"> a callable function, or a SQL clause.""" </span><span class="cx"> def __init__(self, arg): </span><span class="cx"> self.arg = arg </span><del>- def accept_visitor(self, visitor): </del><ins>+ def accept_schema_visitor(self, visitor): </ins><span class="cx"> """calls the visit_column_default method on the given visitor.""" </span><span class="cx"> return visitor.visit_column_default(self) </span><span class="cx"> def __repr__(self): </span><span class="lines">@@ -461,7 +421,7 @@ </span><span class="cx"> ["%s=%s" % (k, repr(getattr(self, k))) for k in ['start', 'increment', 'optional']] </span><span class="cx"> , ',') </span><span class="cx"> </span><del>- def accept_visitor(self, visitor): </del><ins>+ def accept_schema_visitor(self, visitor): </ins><span class="cx"> """calls the visit_seauence method on the given visitor.""" </span><span class="cx"> return visitor.visit_sequence(self) </span><span class="cx"> </span><span class="lines">@@ -486,6 +446,7 @@ </span><span class="cx"> self.unique = kw.pop('unique', False) </span><span class="cx"> self._init_items() </span><span class="cx"> </span><ins>+ engine = property(lambda s:s.table.engine) </ins><span class="cx"> def _init_items(self): </span><span class="cx"> # make sure all columns are from the same table </span><span class="cx"> # FIXME: and no column is repeated </span><span class="lines">@@ -499,10 +460,13 @@ </span><span class="cx"> "%s is from %s not %s" % (column, </span><span class="cx"> column.table, </span><span class="cx"> self.table)) </span><del>- # set my _impl from col.table.engine - self._impl = self.table.engine.indeximpl(self) - - def accept_visitor(self, visitor): </del><ins>+ def create(self): + self.engine.create(self) + def drop(self): + self.engine.drop(self) + def execute(self): + self.create() + def accept_schema_visitor(self, visitor): </ins><span class="cx"> visitor.visit_index(self) </span><span class="cx"> def __str__(self): </span><span class="cx"> return repr(self) </span><span class="lines">@@ -515,24 +479,13 @@ </span><span class="cx"> class SchemaEngine(object): </span><span class="cx"> """a factory object used to create implementations for schema objects. This object </span><span class="cx"> is the ultimate base class for the engine.SQLEngine class.""" </span><del>- def tableimpl(self, table): - """returns a new implementation object for a Table (usually sql.TableImpl)""" - raise NotImplementedError() - def columnimpl(self, column): - """returns a new implementation object for a Column (usually sql.ColumnImpl)""" - raise NotImplementedError() - def indeximpl(self, index): - """returns a new implementation object for an Index (usually - sql.IndexImpl) - """ - raise NotImplementedError() </del><span class="cx"> def reflecttable(self, table): </span><span class="cx"> """given a table, will query the database and populate its Column and ForeignKey </span><span class="cx"> objects.""" </span><span class="cx"> raise NotImplementedError() </span><span class="cx"> </span><del>-class SchemaVisitor(object): - """base class for an object that traverses across Schema structures.""" </del><ins>+class SchemaVisitor(sql.ClauseVisitor): + """defines the visiting for SchemaItem objects""" </ins><span class="cx"> def visit_schema(self, schema): </span><span class="cx"> """visit a generic SchemaItem""" </span><span class="cx"> pass </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemysqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/sql.py (1038 => 1039)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/sql.py 2006-02-25 07:06:09 UTC (rev 1038) +++ sqlalchemy/trunk/lib/sqlalchemy/sql.py 2006-02-25 07:12:50 UTC (rev 1039) </span><span class="lines">@@ -13,7 +13,7 @@ </span><span class="cx"> import string, re, random </span><span class="cx"> types = __import__('types') </span><span class="cx"> </span><del>-__all__ = ['text', 'column', 'func', 'select', 'update', 'insert', 'delete', 'join', 'and_', 'or_', 'not_', 'union', 'union_all', 'desc', 'asc', 'outerjoin', 'alias', 'subquery', 'literal', 'bindparam', 'exists'] </del><ins>+__all__ = ['text', 'table', 'column', 'func', 'select', 'update', 'insert', 'delete', 'join', 'and_', 'or_', 'not_', 'union', 'union_all', 'desc', 'asc', 'outerjoin', 'alias', 'subquery', 'literal', 'bindparam', 'exists'] </ins><span class="cx"> </span><span class="cx"> def desc(column): </span><span class="cx"> """returns a descending ORDER BY clause element, e.g.: </span><span class="lines">@@ -160,11 +160,15 @@ </span><span class="cx"> """returns a Label object for the given selectable, used in the column list for a select statement.""" </span><span class="cx"> return Label(name, obj) </span><span class="cx"> </span><del>-def column(table, text): - """returns a textual column clause, relative to a table. this differs from using straight text - or text() in that the column is treated like a regular column, i.e. gets added to a Selectable's list - of columns.""" - return ColumnClause(text, table) </del><ins>+def column(text, table=None, type=None): + """returns a textual column clause, relative to a table. this is also the primitive version of + a schema.Column which is a subclass. """ + return ColumnClause(text, table, type) + +def table(name, *columns): + """returns a table clause. this is a primitive version of the schema.Table object, which is a subclass + of this object.""" + return TableClause(name, *columns) </ins><span class="cx"> </span><span class="cx"> def bindparam(key, value = None, type=None): </span><span class="cx"> """creates a bind parameter clause with the given key. </span><span class="lines">@@ -172,7 +176,7 @@ </span><span class="cx"> An optional default value can be specified by the value parameter, and the optional type parameter </span><span class="cx"> is a sqlalchemy.types.TypeEngine object which indicates bind-parameter and result-set translation for </span><span class="cx"> this bind parameter.""" </span><del>- if isinstance(key, schema.Column): </del><ins>+ if isinstance(key, ColumnClause): </ins><span class="cx"> return BindParamClause(key.name, value, type=key.type) </span><span class="cx"> else: </span><span class="cx"> return BindParamClause(key, value, type=type) </span><span class="lines">@@ -190,7 +194,7 @@ </span><span class="cx"> text - the text of the SQL statement to be created. use :<param> to specify </span><span class="cx"> bind parameters; they will be compiled to their engine-specific format. </span><span class="cx"> </span><del>- engine - the engine to be used for this text query. Alternatively, call the </del><ins>+ engine - an optional engine to be used for this text query. Alternatively, call the </ins><span class="cx"> text() method off the engine directly. </span><span class="cx"> </span><span class="cx"> bindparams - a list of bindparam() instances which can be used to define the </span><span class="lines">@@ -222,15 +226,15 @@ </span><span class="cx"> return CompoundSelect(keyword, *selects, **kwargs) </span><span class="cx"> </span><span class="cx"> def _is_literal(element): </span><del>- return not isinstance(element, ClauseElement) and not isinstance(element, schema.SchemaItem) </del><ins>+ return not isinstance(element, ClauseElement) </ins><span class="cx"> </span><span class="cx"> def is_column(col): </span><del>- return isinstance(col, schema.Column) or isinstance(col, ColumnElement) </del><ins>+ return isinstance(col, ColumnElement) </ins><span class="cx"> </span><del>-class ClauseVisitor(schema.SchemaVisitor): - """builds upon SchemaVisitor to define the visiting of SQL statement elements in - addition to Schema elements.""" - def visit_columnclause(self, column):pass </del><ins>+class ClauseVisitor(object): + """Defines the visiting of ClauseElements.""" + def visit_column(self, column):pass + def visit_table(self, column):pass </ins><span class="cx"> def visit_fromclause(self, fromclause):pass </span><span class="cx"> def visit_bindparam(self, bindparam):pass </span><span class="cx"> def visit_textclause(self, textclause):pass </span><span class="lines">@@ -309,18 +313,6 @@ </span><span class="cx"> </span><span class="cx"> class ClauseElement(object): </span><span class="cx"> """base class for elements of a programmatically constructed SQL expression.""" </span><del>- def hash_key(self): - """returns a string that uniquely identifies the concept this ClauseElement - represents. - - two ClauseElements can have the same value for hash_key() iff they both correspond to - the exact same generated SQL. This allows the hash_key() values of a collection of - ClauseElements to be constructed into a larger identifying string for the purpose of - caching a SQL expression. - - Note that since ClauseElements may be mutable, the hash_key() value is subject to - change if the underlying structure of the ClauseElement changes.""" - raise NotImplementedError(repr(self)) </del><span class="cx"> def _get_from_objects(self): </span><span class="cx"> """returns objects represented in this ClauseElement that should be added to the </span><span class="cx"> FROM list of a query.""" </span><span class="lines">@@ -357,19 +349,24 @@ </span><span class="cx"> return False </span><span class="cx"> </span><span class="cx"> def _find_engine(self): </span><ins>+ """default strategy for locating an engine within the clause element. + relies upon a local engine property, or looks in the "from" objects which + ultimately have to contain Tables or TableClauses. """ </ins><span class="cx"> try: </span><span class="cx"> if self._engine is not None: </span><span class="cx"> return self._engine </span><span class="cx"> except AttributeError: </span><span class="cx"> pass </span><span class="cx"> for f in self._get_from_objects(): </span><ins>+ if f is self: + continue </ins><span class="cx"> engine = f.engine </span><span class="cx"> if engine is not None: </span><span class="cx"> return engine </span><span class="cx"> else: </span><span class="cx"> return None </span><span class="cx"> </span><del>- engine = property(lambda s: s._find_engine()) </del><ins>+ engine = property(lambda s: s._find_engine(), doc="attempts to locate a SQLEngine within this ClauseElement structure, or returns None if none found.") </ins><span class="cx"> </span><span class="cx"> def compile(self, engine = None, parameters = None, typemap=None): </span><span class="cx"> """compiles this SQL expression using its underlying SQLEngine to produce </span><span class="lines">@@ -380,16 +377,13 @@ </span><span class="cx"> engine = self.engine </span><span class="cx"> </span><span class="cx"> if engine is None: </span><del>- raise InvalidRequestError("no SQLEngine could be located within this ClauseElement.") </del><ins>+ import sqlalchemy.ansisql as ansisql + engine = ansisql.engine() </ins><span class="cx"> </span><span class="cx"> return engine.compile(self, parameters=parameters, typemap=typemap) </span><span class="cx"> </span><span class="cx"> def __str__(self): </span><del>- e = self.engine - if e is None: - import sqlalchemy.ansisql as ansisql - e = ansisql.engine() - return str(self.compile(e)) </del><ins>+ return str(self.compile()) </ins><span class="cx"> </span><span class="cx"> def execute(self, *multiparams, **params): </span><span class="cx"> """compiles and executes this SQL expression using its underlying SQLEngine. the </span><span class="lines">@@ -425,6 +419,7 @@ </span><span class="cx"> return not_(self) </span><span class="cx"> </span><span class="cx"> class CompareMixin(object): </span><ins>+ """defines comparison operations for ClauseElements.""" </ins><span class="cx"> def __lt__(self, other): </span><span class="cx"> return self._compare('<', other) </span><span class="cx"> def __le__(self, other): </span><span class="lines">@@ -500,19 +495,15 @@ </span><span class="cx"> </span><span class="cx"> def accept_visitor(self, visitor): </span><span class="cx"> raise NotImplementedError(repr(self)) </span><del>- </del><span class="cx"> def is_selectable(self): </span><span class="cx"> return True </span><del>- </del><span class="cx"> def select(self, whereclauses = None, **params): </span><span class="cx"> return select([self], whereclauses, **params) </span><del>- </del><span class="cx"> def _group_parenthesized(self): </span><span class="cx"> """indicates if this Selectable requires parenthesis when grouped into a compound </span><span class="cx"> statement""" </span><span class="cx"> return True </span><span class="cx"> </span><del>- </del><span class="cx"> class ColumnElement(Selectable, CompareMixin): </span><span class="cx"> """represents a column element within the list of a Selectable's columns. ... [truncated message content] |
From: <co...@sq...> - 2006-02-25 07:06: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>[1038] sqlalchemy/branches/sql_rearrangement/CHANGES: update</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1038</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-02-25 01:06:09 -0600 (Sat, 25 Feb 2006)</dd> </dl> <h3>Log Message</h3> <pre>update</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchessql_rearrangementCHANGES">sqlalchemy/branches/sql_rearrangement/CHANGES</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchessql_rearrangementCHANGES"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/sql_rearrangement/CHANGES (1037 => 1038)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/sql_rearrangement/CHANGES 2006-02-25 07:04:54 UTC (rev 1037) +++ sqlalchemy/branches/sql_rearrangement/CHANGES 2006-02-25 07:06:09 UTC (rev 1038) </span><span class="lines">@@ -2,6 +2,9 @@ </span><span class="cx"> - fix to Oracle "row_number over" clause with mulitple tables </span><span class="cx"> - mapper.get() was not selecting multiple-keyed objects if the mapper's table was a join, </span><span class="cx"> such as in an inheritance relationship, this is fixed. </span><ins>+- overhaul to sql/schema packages so that the sql package can run all on its own, +producing selects, inserts, etc. without any engine dependencies. Table/Column +are the "physical" subclasses of TableClause/ColumnClause. </ins><span class="cx"> 0.1.2 </span><span class="cx"> - fixed a recursive call in schema that was somehow running 994 times then returning </span><span class="cx"> normally. broke nothing, slowed down everything. thanks to jpellerin for finding this. </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-02-25 07:05:04
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head><style type="text/css"><!-- #msg dl { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; } #msg dt { float: left; width: 6em; font-weight: bold; } #msg dt:after { content:':';} #msg dl, #msg dt, #msg ul, #msg li { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; } #msg dl a { font-weight: bold} #msg dl a:link { color:#fc3; } #msg dl a:active { color:#ff0; } #msg dl a:visited { color:#cc6; } h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; } #msg pre { overflow: auto; background: #ffc; border: 1px #fc0 solid; padding: 6px; } #msg ul, pre { overflow: auto; } #patch { width: 100%; } #patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;} #patch .propset h4, #patch .binary h4 {margin:0;} #patch pre {padding:0;line-height:1.2em;margin:0;} #patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;} #patch .propset .diff, #patch .binary .diff {padding:10px 0;} #patch span {display:block;padding:0 10px;} #patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;} #patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;} #patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;} #patch .lines, .info {color:#888;background:#fff;} --></style> <title>[1037] sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/mapping/objectstore.py: fixed import_instance</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1037</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-02-25 01:04:54 -0600 (Sat, 25 Feb 2006)</dd> </dl> <h3>Log Message</h3> <pre>fixed import_instance</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchessql_rearrangementlibsqlalchemymappingobjectstorepy">sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/mapping/objectstore.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchessql_rearrangementlibsqlalchemymappingobjectstorepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/mapping/objectstore.py (1036 => 1037)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/mapping/objectstore.py 2006-02-25 07:00:54 UTC (rev 1036) +++ sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/mapping/objectstore.py 2006-02-25 07:04:54 UTC (rev 1037) </span><span class="lines">@@ -181,7 +181,6 @@ </span><span class="cx"> return None </span><span class="cx"> key = getattr(instance, '_instance_key', None) </span><span class="cx"> mapper = object_mapper(instance) </span><del>- key = (key[0], mapper.table.hash_key(), key[2]) </del><span class="cx"> u = self.uow </span><span class="cx"> if key is not None: </span><span class="cx"> if u.identity_map.has_key(key): </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-02-25 07:01:03
|
<!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>[1036] sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/schema.py: dev</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1036</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-02-25 01:00:54 -0600 (Sat, 25 Feb 2006)</dd> </dl> <h3>Log Message</h3> <pre>dev</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchessql_rearrangementlibsqlalchemyschemapy">sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/schema.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchessql_rearrangementlibsqlalchemyschemapy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/schema.py (1035 => 1036)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/schema.py 2006-02-25 06:55:41 UTC (rev 1035) +++ sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/schema.py 2006-02-25 07:00:54 UTC (rev 1036) </span><span class="lines">@@ -78,7 +78,9 @@ </span><span class="cx"> </span><span class="cx"> </span><span class="cx"> class Table(sql.TableClause, SchemaItem): </span><del>- """represents a relational database table. </del><ins>+ """represents a relational database table. This subclasses sql.TableClause to provide + a table that is "wired" to an engine. Whereas TableClause represents a table as its + used in a SQL expression, Table represents a table as its created in the database. </ins><span class="cx"> </span><span class="cx"> Be sure to look at sqlalchemy.sql.TableImpl for additional methods defined on a Table.""" </span><span class="cx"> __metaclass__ = TableSingleton </span><span class="lines">@@ -191,7 +193,8 @@ </span><span class="cx"> return Table(self.name, engine, schema=schema, *args) </span><span class="cx"> </span><span class="cx"> class Column(sql.ColumnClause, SchemaItem): </span><del>- """represents a column in a database table.""" </del><ins>+ """represents a column in a database table. this is a subclass of sql.ColumnClause and + represents an actual existing table in the database, in a similar fashion as TableClause/Table.""" </ins><span class="cx"> def __init__(self, name, type, *args, **kwargs): </span><span class="cx"> """constructs a new Column object. Arguments are: </span><span class="cx"> </span><span class="lines">@@ -476,17 +479,6 @@ </span><span class="cx"> class SchemaEngine(object): </span><span class="cx"> """a factory object used to create implementations for schema objects. This object </span><span class="cx"> is the ultimate base class for the engine.SQLEngine class.""" </span><del>- def tableimpl(self, table): - """returns a new implementation object for a Table (usually sql.TableImpl)""" - raise NotImplementedError() - def columnimpl(self, column): - """returns a new implementation object for a Column (usually sql.ColumnImpl)""" - raise NotImplementedError() - def indeximpl(self, index): - """returns a new implementation object for an Index (usually - sql.IndexImpl) - """ - raise NotImplementedError() </del><span class="cx"> def reflecttable(self, table): </span><span class="cx"> """given a table, will query the database and populate its Column and ForeignKey </span><span class="cx"> objects.""" </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-02-25 06:55:53
|
<!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>[1035] sqlalchemy/branches/sql_rearrangement/test: dev</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1035</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-02-25 00:55:41 -0600 (Sat, 25 Feb 2006)</dd> </dl> <h3>Log Message</h3> <pre>dev</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchessql_rearrangementlibsqlalchemyschemapy">sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/schema.py</a></li> <li><a href="#sqlalchemybranchessql_rearrangementlibsqlalchemysqlpy">sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/sql.py</a></li> <li><a href="#sqlalchemybranchessql_rearrangementtestselectpy">sqlalchemy/branches/sql_rearrangement/test/select.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchessql_rearrangementlibsqlalchemyschemapy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/schema.py (1034 => 1035)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/schema.py 2006-02-25 06:29:51 UTC (rev 1034) +++ sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/schema.py 2006-02-25 06:55:41 UTC (rev 1035) </span><span class="lines">@@ -493,7 +493,7 @@ </span><span class="cx"> raise NotImplementedError() </span><span class="cx"> </span><span class="cx"> class SchemaVisitor(sql.ClauseVisitor): </span><del>- """base class for an object that traverses across Schema structures.""" </del><ins>+ """defines the visiting for SchemaItem objects""" </ins><span class="cx"> def visit_schema(self, schema): </span><span class="cx"> """visit a generic SchemaItem""" </span><span class="cx"> pass </span></span></pre></div> <a id="sqlalchemybranchessql_rearrangementlibsqlalchemysqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/sql.py (1034 => 1035)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/sql.py 2006-02-25 06:29:51 UTC (rev 1034) +++ sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/sql.py 2006-02-25 06:55:41 UTC (rev 1035) </span><span class="lines">@@ -161,11 +161,13 @@ </span><span class="cx"> return Label(name, obj) </span><span class="cx"> </span><span class="cx"> def column(text, table=None, type=None): </span><del>- """returns a textual column clause, relative to a table. this differs from using straight text - or text() in that the column is treated like a regular column, i.e. gets added to a Selectable's list of columns.""" </del><ins>+ """returns a textual column clause, relative to a table. this is also the primitive version of + a schema.Column which is a subclass. """ </ins><span class="cx"> return ColumnClause(text, table, type) </span><span class="cx"> </span><span class="cx"> def table(name, *columns): </span><ins>+ """returns a table clause. this is a primitive version of the schema.Table object, which is a subclass + of this object.""" </ins><span class="cx"> return TableClause(name, *columns) </span><span class="cx"> </span><span class="cx"> def bindparam(key, value = None, type=None): </span><span class="lines">@@ -192,7 +194,7 @@ </span><span class="cx"> text - the text of the SQL statement to be created. use :<param> to specify </span><span class="cx"> bind parameters; they will be compiled to their engine-specific format. </span><span class="cx"> </span><del>- engine - the engine to be used for this text query. Alternatively, call the </del><ins>+ engine - an optional engine to be used for this text query. Alternatively, call the </ins><span class="cx"> text() method off the engine directly. </span><span class="cx"> </span><span class="cx"> bindparams - a list of bindparam() instances which can be used to define the </span><span class="lines">@@ -230,8 +232,7 @@ </span><span class="cx"> return isinstance(col, ColumnElement) </span><span class="cx"> </span><span class="cx"> class ClauseVisitor(object): </span><del>- """builds upon SchemaVisitor to define the visiting of SQL statement elements in - addition to Schema elements.""" </del><ins>+ """Defines the visiting of ClauseElements.""" </ins><span class="cx"> def visit_column(self, column):pass </span><span class="cx"> def visit_table(self, column):pass </span><span class="cx"> def visit_fromclause(self, fromclause):pass </span><span class="lines">@@ -348,6 +349,9 @@ </span><span class="cx"> return False </span><span class="cx"> </span><span class="cx"> def _find_engine(self): </span><ins>+ """default strategy for locating an engine within the clause element. + relies upon a local engine property, or looks in the "from" objects which + ultimately have to contain Tables or TableClauses. """ </ins><span class="cx"> try: </span><span class="cx"> if self._engine is not None: </span><span class="cx"> return self._engine </span><span class="lines">@@ -362,7 +366,7 @@ </span><span class="cx"> else: </span><span class="cx"> return None </span><span class="cx"> </span><del>- engine = property(lambda s: s._find_engine()) </del><ins>+ engine = property(lambda s: s._find_engine(), doc="attempts to locate a SQLEngine within this ClauseElement structure, or returns None if none found.") </ins><span class="cx"> </span><span class="cx"> def compile(self, engine = None, parameters = None, typemap=None): </span><span class="cx"> """compiles this SQL expression using its underlying SQLEngine to produce </span><span class="lines">@@ -373,16 +377,13 @@ </span><span class="cx"> engine = self.engine </span><span class="cx"> </span><span class="cx"> if engine is None: </span><del>- raise InvalidRequestError("no SQLEngine could be located within this ClauseElement.") </del><ins>+ import sqlalchemy.ansisql as ansisql + engine = ansisql.engine() </ins><span class="cx"> </span><span class="cx"> return engine.compile(self, parameters=parameters, typemap=typemap) </span><span class="cx"> </span><span class="cx"> def __str__(self): </span><del>- e = self.engine - if e is None: - import sqlalchemy.ansisql as ansisql - e = ansisql.engine() - return str(self.compile(e)) </del><ins>+ return str(self.compile()) </ins><span class="cx"> </span><span class="cx"> def execute(self, *multiparams, **params): </span><span class="cx"> """compiles and executes this SQL expression using its underlying SQLEngine. the </span><span class="lines">@@ -418,6 +419,7 @@ </span><span class="cx"> return not_(self) </span><span class="cx"> </span><span class="cx"> class CompareMixin(object): </span><ins>+ """defines comparison operations for ClauseElements.""" </ins><span class="cx"> def __lt__(self, other): </span><span class="cx"> return self._compare('<', other) </span><span class="cx"> def __le__(self, other): </span><span class="lines">@@ -493,19 +495,15 @@ </span><span class="cx"> </span><span class="cx"> def accept_visitor(self, visitor): </span><span class="cx"> raise NotImplementedError(repr(self)) </span><del>- </del><span class="cx"> def is_selectable(self): </span><span class="cx"> return True </span><del>- </del><span class="cx"> def select(self, whereclauses = None, **params): </span><span class="cx"> return select([self], whereclauses, **params) </span><del>- </del><span class="cx"> def _group_parenthesized(self): </span><span class="cx"> """indicates if this Selectable requires parenthesis when grouped into a compound </span><span class="cx"> statement""" </span><span class="cx"> return True </span><span class="cx"> </span><del>- </del><span class="cx"> class ColumnElement(Selectable, CompareMixin): </span><span class="cx"> """represents a column element within the list of a Selectable's columns. Provides </span><span class="cx"> default implementations for the things a "column" needs, including a "primary_key" flag, </span><span class="lines">@@ -856,13 +854,9 @@ </span><span class="cx"> return and_(*crit) </span><span class="cx"> </span><span class="cx"> def _group_parenthesized(self): </span><del>- """indicates if this Selectable requires parenthesis when grouped into a compound - statement""" </del><span class="cx"> return True </span><del>- </del><span class="cx"> def select(self, whereclauses = None, **params): </span><span class="cx"> return select([self.left, self.right], whereclauses, from_obj=[self], **params) </span><del>- </del><span class="cx"> def accept_visitor(self, visitor): </span><span class="cx"> self.left.accept_visitor(visitor) </span><span class="cx"> self.right.accept_visitor(visitor) </span><span class="lines">@@ -948,9 +942,8 @@ </span><span class="cx"> return self.obj._make_proxy(selectable, name=self.name) </span><span class="cx"> </span><span class="cx"> class ColumnClause(ColumnElement): </span><del>- """represents a textual column clause in a SQL statement. ColumnClause operates - in two modes, one where its just any text that will be placed into the select statement, - and "column" mode, where it represents a column attached to a table.""" </del><ins>+ """represents a textual column clause in a SQL statement. May or may not + be bound to an underlying Selectable.""" </ins><span class="cx"> def __init__(self, text, selectable=None, type=None): </span><span class="cx"> self.key = self.name = self.text = text </span><span class="cx"> self.table = selectable </span><span class="lines">@@ -961,7 +954,6 @@ </span><span class="cx"> else: </span><span class="cx"> return self.text </span><span class="cx"> _label = property(_get_label) </span><del>- default_label = property(lambda s:s._label) </del><span class="cx"> def accept_visitor(self, visitor): </span><span class="cx"> visitor.visit_column(self) </span><span class="cx"> def _get_from_objects(self): </span></span></pre></div> <a id="sqlalchemybranchessql_rearrangementtestselectpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/sql_rearrangement/test/select.py (1034 => 1035)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/sql_rearrangement/test/select.py 2006-02-25 06:29:51 UTC (rev 1034) +++ sqlalchemy/branches/sql_rearrangement/test/select.py 2006-02-25 06:55:41 UTC (rev 1035) </span><span class="lines">@@ -10,6 +10,10 @@ </span><span class="cx"> from testbase import PersistTest </span><span class="cx"> import unittest, re </span><span class="cx"> </span><ins>+# the select test now tests almost completely with TableClause/ColumnClause objects, +# which are free-roaming table/column objects not attached to any database. +# so SQLAlchemy's SQL construction engine can be used with no database dependencies at all. + </ins><span class="cx"> table1 = table('mytable', </span><span class="cx"> column('myid'), </span><span class="cx"> column('name'), </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-02-25 06:30:07
|
<!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>[1034] sqlalchemy/branches/sql_rearrangement/test: unit tests pass</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1034</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-02-25 00:29:51 -0600 (Sat, 25 Feb 2006)</dd> </dl> <h3>Log Message</h3> <pre>unit tests pass</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchessql_rearrangementlibsqlalchemyansisqlpy">sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/ansisql.py</a></li> <li><a href="#sqlalchemybranchessql_rearrangementlibsqlalchemydatabasesmysqlpy">sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/databases/mysql.py</a></li> <li><a href="#sqlalchemybranchessql_rearrangementlibsqlalchemydatabasespostgrespy">sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/databases/postgres.py</a></li> <li><a href="#sqlalchemybranchessql_rearrangementlibsqlalchemyenginepy">sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/engine.py</a></li> <li><a href="#sqlalchemybranchessql_rearrangementlibsqlalchemyextproxypy">sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/ext/proxy.py</a></li> <li><a href="#sqlalchemybranchessql_rearrangementlibsqlalchemymappingobjectstorepy">sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/mapping/objectstore.py</a></li> <li><a href="#sqlalchemybranchessql_rearrangementlibsqlalchemyschemapy">sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/schema.py</a></li> <li><a href="#sqlalchemybranchessql_rearrangementlibsqlalchemysqlpy">sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/sql.py</a></li> <li><a href="#sqlalchemybranchessql_rearrangementlibsqlalchemyutilpy">sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/util.py</a></li> <li><a href="#sqlalchemybranchessql_rearrangementtestobjectstorepy">sqlalchemy/branches/sql_rearrangement/test/objectstore.py</a></li> <li><a href="#sqlalchemybranchessql_rearrangementtestquerypy">sqlalchemy/branches/sql_rearrangement/test/query.py</a></li> <li><a href="#sqlalchemybranchessql_rearrangementtestselectpy">sqlalchemy/branches/sql_rearrangement/test/select.py</a></li> <li><a href="#sqlalchemybranchessql_rearrangementtesttestbasepy">sqlalchemy/branches/sql_rearrangement/test/testbase.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchessql_rearrangementlibsqlalchemyansisqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/ansisql.py (1033 => 1034)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/ansisql.py 2006-02-25 05:32:54 UTC (rev 1033) +++ sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/ansisql.py 2006-02-25 06:29:51 UTC (rev 1034) </span><span class="lines">@@ -35,7 +35,7 @@ </span><span class="cx"> def dbapi(self): </span><span class="cx"> return None </span><span class="cx"> </span><del>-class ANSICompiler(sql.Compiled, schema.SchemaVisitor): </del><ins>+class ANSICompiler(sql.Compiled): </ins><span class="cx"> """default implementation of Compiled, which compiles ClauseElements into ANSI-compliant SQL strings.""" </span><span class="cx"> def __init__(self, engine, statement, parameters=None, typemap=None, **kwargs): </span><span class="cx"> """constructs a new ANSICompiler object. </span><span class="lines">@@ -392,8 +392,8 @@ </span><span class="cx"> self.visit_insert_sequence(c, seq) </span><span class="cx"> vis = DefaultVisitor() </span><span class="cx"> for c in insert_stmt.table.c: </span><del>- if (self.parameters is None or self.parameters.get(c.key, None) is None): - c.accept_visitor(vis) </del><ins>+ if (isinstance(c, schema.SchemaItem) and (self.parameters is None or self.parameters.get(c.key, None) is None)): + c.accept_schema_visitor(vis) </ins><span class="cx"> </span><span class="cx"> self.isinsert = True </span><span class="cx"> colparams = self._get_colparams(insert_stmt) </span></span></pre></div> <a id="sqlalchemybranchessql_rearrangementlibsqlalchemydatabasesmysqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/databases/mysql.py (1033 => 1034)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/databases/mysql.py 2006-02-25 05:32:54 UTC (rev 1033) +++ sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/databases/mysql.py 2006-02-25 06:29:51 UTC (rev 1034) </span><span class="lines">@@ -131,11 +131,6 @@ </span><span class="cx"> def supports_sane_rowcount(self): </span><span class="cx"> return False </span><span class="cx"> </span><del>- def tableimpl(self, table, **kwargs): - """returns a new sql.TableImpl object to correspond to the given Table object.""" - mysql_engine = kwargs.pop('mysql_engine', None) - return MySQLTableImpl(table, mysql_engine=mysql_engine) - </del><span class="cx"> def compiler(self, statement, bindparams, **kwargs): </span><span class="cx"> return MySQLCompiler(self, statement, bindparams, **kwargs) </span><span class="cx"> </span><span class="lines">@@ -175,7 +170,7 @@ </span><span class="cx"> #ischema.reflecttable(self, table, ischema_names, use_mysql=True) </span><span class="cx"> </span><span class="cx"> tabletype, foreignkeyD = self.moretableinfo(table=table) </span><del>- table._impl.mysql_engine = tabletype </del><ins>+ table.kwargs['mysql_engine'] = tabletype </ins><span class="cx"> </span><span class="cx"> c = self.execute("describe " + table.name, {}) </span><span class="cx"> while True: </span><span class="lines">@@ -235,14 +230,6 @@ </span><span class="cx"> return (tabletype, foreignkeyD) </span><span class="cx"> </span><span class="cx"> </span><del>-class MySQLTableImpl(sql.TableImpl): - """attached to a schema.Table to provide it with a Selectable interface - as well as other functions - """ - def __init__(self, table, mysql_engine=None): - super(MySQLTableImpl, self).__init__(table) - self.mysql_engine = mysql_engine - </del><span class="cx"> class MySQLCompiler(ansisql.ANSICompiler): </span><span class="cx"> </span><span class="cx"> def visit_function(self, func): </span><span class="lines">@@ -277,12 +264,13 @@ </span><span class="cx"> if first_pk and isinstance(column.type, types.Integer): </span><span class="cx"> colspec += " AUTO_INCREMENT" </span><span class="cx"> if column.foreign_key: </span><del>- colspec += ", FOREIGN KEY (%s) REFERENCES %s(%s)" % (column.name, column.column.foreign_key.column.table.name, column.column.foreign_key.column.name) </del><ins>+ colspec += ", FOREIGN KEY (%s) REFERENCES %s(%s)" % (column.name, column.foreign_key.column.table.name, column.foreign_key.column.name) </ins><span class="cx"> return colspec </span><span class="cx"> </span><span class="cx"> def post_create_table(self, table): </span><del>- if table.mysql_engine is not None: - return " ENGINE=%s" % table.mysql_engine </del><ins>+ mysql_engine = table.kwargs.get('mysql_engine', None) + if mysql_engine is not None: + return " ENGINE=%s" % mysql_engine </ins><span class="cx"> else: </span><span class="cx"> return "" </span><span class="cx"> </span></span></pre></div> <a id="sqlalchemybranchessql_rearrangementlibsqlalchemydatabasespostgrespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/databases/postgres.py (1033 => 1034)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/databases/postgres.py 2006-02-25 05:32:54 UTC (rev 1033) +++ sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/databases/postgres.py 2006-02-25 06:29:51 UTC (rev 1034) </span><span class="lines">@@ -312,7 +312,7 @@ </span><span class="cx"> if column.primary_key and not override_pk: </span><span class="cx"> colspec += " PRIMARY KEY" </span><span class="cx"> if column.foreign_key: </span><del>- colspec += " REFERENCES %s(%s)" % (column.column.foreign_key.column.table.fullname, column.column.foreign_key.column.name) </del><ins>+ colspec += " REFERENCES %s(%s)" % (column.foreign_key.column.table.fullname, column.foreign_key.column.name) </ins><span class="cx"> return colspec </span><span class="cx"> </span><span class="cx"> def visit_sequence(self, sequence): </span></span></pre></div> <a id="sqlalchemybranchessql_rearrangementlibsqlalchemyenginepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/engine.py (1033 => 1034)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/engine.py 2006-02-25 05:32:54 UTC (rev 1033) +++ sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/engine.py 2006-02-25 06:29:51 UTC (rev 1034) </span><span class="lines">@@ -130,7 +130,7 @@ </span><span class="cx"> </span><span class="cx"> def get_column_default(self, column): </span><span class="cx"> if column.default is not None: </span><del>- return column.default.accept_visitor(self) </del><ins>+ return column.default.accept_schema_visitor(self) </ins><span class="cx"> else: </span><span class="cx"> return None </span><span class="cx"> </span><span class="lines">@@ -295,11 +295,11 @@ </span><span class="cx"> </span><span class="cx"> def create(self, entity, **params): </span><span class="cx"> """creates a table or index within this engine's database connection given a schema.Table object.""" </span><del>- entity.accept_visitor(self.schemagenerator(**params)) </del><ins>+ entity.accept_schema_visitor(self.schemagenerator(**params)) </ins><span class="cx"> </span><span class="cx"> def drop(self, entity, **params): </span><span class="cx"> """drops a table or index within this engine's database connection given a schema.Table object.""" </span><del>- entity.accept_visitor(self.schemadropper(**params)) </del><ins>+ entity.accept_schema_visitor(self.schemadropper(**params)) </ins><span class="cx"> </span><span class="cx"> def compile(self, statement, parameters, **kwargs): </span><span class="cx"> """given a sql.ClauseElement statement plus optional bind parameters, creates a new </span></span></pre></div> <a id="sqlalchemybranchessql_rearrangementlibsqlalchemyextproxypy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/ext/proxy.py (1033 => 1034)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/ext/proxy.py 2006-02-25 05:32:54 UTC (rev 1033) +++ sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/ext/proxy.py 2006-02-25 06:29:51 UTC (rev 1034) </span><span class="lines">@@ -13,7 +13,7 @@ </span><span class="cx"> """ </span><span class="cx"> SQLEngine proxy. Supports lazy and late initialization by </span><span class="cx"> delegating to a real engine (set with connect()), and using proxy </span><del>- classes for TableImpl, ColumnImpl and TypeEngine. </del><ins>+ classes for TypeEngine. </ins><span class="cx"> """ </span><span class="cx"> </span><span class="cx"> def __init__(self): </span><span class="lines">@@ -61,15 +61,6 @@ </span><span class="cx"> return None </span><span class="cx"> return self.get_engine().oid_column_name() </span><span class="cx"> </span><del>- def columnimpl(self, column): - """Proxy point: return a ProxyColumnImpl - """ - return ProxyColumnImpl(self, column) - - def tableimpl(self, table): - """Proxy point: return a ProxyTableImpl - """ - return ProxyTableImpl(self, table) </del><span class="cx"> </span><span class="cx"> def type_descriptor(self, typeobj): </span><span class="cx"> """Proxy point: return a ProxyTypeEngine </span><span class="lines">@@ -84,45 +75,6 @@ </span><span class="cx"> raise AttributeError('No connection established in ProxyEngine: ' </span><span class="cx"> ' no access to %s' % attr) </span><span class="cx"> </span><del>- -class ProxyColumnImpl(sql.ColumnImpl): - """Proxy column; defers engine access to ProxyEngine - """ - def __init__(self, engine, column): - sql.ColumnImpl.__init__(self, column) - self._engine = engine - self.impls = weakref.WeakKeyDictionary() - def _get_impl(self): - e = self._engine.engine - try: - return self.impls[e] - except KeyError: - impl = e.columnimpl(self.column) - self.impls[e] = impl - def __getattr__(self, key): - return getattr(self._get_impl(), key) - engine = property(lambda self: self._engine.engine) - -class ProxyTableImpl(sql.TableImpl): - """Proxy table; defers engine access to ProxyEngine - """ - def __init__(self, engine, table): - sql.TableImpl.__init__(self, table) - self._engine = engine - self.impls = weakref.WeakKeyDictionary() - def _get_impl(self): - e = self._engine.engine - try: - return self.impls[e] - except KeyError: - impl = e.tableimpl(self.table) - self.impls[e] = impl - return impl - def __getattr__(self, key): - return getattr(self._get_impl(), key) - - engine = property(lambda self: self._engine.engine) - </del><span class="cx"> class ProxyType(object): </span><span class="cx"> """ProxyType base class; used by ProxyTypeEngine to construct proxying </span><span class="cx"> types </span></span></pre></div> <a id="sqlalchemybranchessql_rearrangementlibsqlalchemymappingobjectstorepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/mapping/objectstore.py (1033 => 1034)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/mapping/objectstore.py 2006-02-25 05:32:54 UTC (rev 1033) +++ sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/mapping/objectstore.py 2006-02-25 06:29:51 UTC (rev 1034) </span><span class="lines">@@ -194,11 +194,11 @@ </span><span class="cx"> u.register_new(instance) </span><span class="cx"> return instance </span><span class="cx"> </span><del>-def get_id_key(ident, class_, table): - return Session.get_id_key(ident, class_, table) </del><ins>+def get_id_key(ident, class_): + return Session.get_id_key(ident, class_) </ins><span class="cx"> </span><del>-def get_row_key(row, class_, table, primary_key): - return Session.get_row_key(row, class_, table, primary_key) </del><ins>+def get_row_key(row, class_, primary_key): + return Session.get_row_key(row, class_, primary_key) </ins><span class="cx"> </span><span class="cx"> def begin(): </span><span class="cx"> """begins a new UnitOfWork transaction. the next commit will affect only </span></span></pre></div> <a id="sqlalchemybranchessql_rearrangementlibsqlalchemyschemapy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/schema.py (1033 => 1034)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/schema.py 2006-02-25 05:32:54 UTC (rev 1033) +++ sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/schema.py 2006-02-25 06:29:51 UTC (rev 1034) </span><span class="lines">@@ -123,7 +123,8 @@ </span><span class="cx"> self.fullname = "%s.%s" % (self.schema, self.name) </span><span class="cx"> else: </span><span class="cx"> self.fullname = self.name </span><del>- </del><ins>+ self.kwargs = kwargs + </ins><span class="cx"> def __repr__(self): </span><span class="cx"> return "Table(%s)" % string.join( </span><span class="cx"> [repr(self.name)] + [repr(self.engine)] + </span><span class="lines">@@ -141,10 +142,9 @@ </span><span class="cx"> """clears out the columns and other properties of this Table, and reloads them from the </span><span class="cx"> given argument list. This is used with the "redefine" keyword argument sent to the </span><span class="cx"> metaclass constructor.""" </span><del>- self.columns = OrderedProperties() - self.c = self.columns - self.foreign_keys = [] - self.primary_key = [] </del><ins>+ self._clear() + + print "RELOAD VALUES", args </ins><span class="cx"> self._init_items(*args) </span><span class="cx"> </span><span class="cx"> def append_item(self, item): </span><span class="lines">@@ -162,11 +162,11 @@ </span><span class="cx"> def _set_parent(self, schema): </span><span class="cx"> schema.tables[self.name] = self </span><span class="cx"> self.schema = schema </span><del>- def accept_visitor(self, visitor): </del><ins>+ def accept_schema_visitor(self, visitor): </ins><span class="cx"> """traverses the given visitor across the Column objects inside this Table, </span><span class="cx"> then calls the visit_table method on the visitor.""" </span><span class="cx"> for c in self.columns: </span><del>- c.accept_visitor(visitor) </del><ins>+ c.accept_schema_visitor(visitor) </ins><span class="cx"> return visitor.visit_table(self) </span><span class="cx"> def deregister(self): </span><span class="cx"> """removes this table from it's engines table registry. this does not </span><span class="lines">@@ -237,10 +237,6 @@ </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><del>- if self.default is not None: - self.default = ColumnDefault(self.default) - self.default._set_parent(self) - </del><span class="cx"> primary_key = AttrProp('_primary_key') </span><span class="cx"> foreign_key = AttrProp('_foreign_key') </span><span class="cx"> original = property(lambda s: s._orig or s) </span><span class="lines">@@ -301,13 +297,13 @@ </span><span class="cx"> c._init_items(fk) </span><span class="cx"> return c </span><span class="cx"> </span><del>- def accept_visitor(self, visitor): </del><ins>+ def accept_schema_visitor(self, visitor): </ins><span class="cx"> """traverses the given visitor to this Column's default and foreign key object, </span><span class="cx"> then calls visit_column on the visitor.""" </span><span class="cx"> if self.default is not None: </span><del>- self.default.accept_visitor(visitor) </del><ins>+ self.default.accept_schema_visitor(visitor) </ins><span class="cx"> if self.foreign_key is not None: </span><del>- self.foreign_key.accept_visitor(visitor) </del><ins>+ self.foreign_key.accept_schema_visitor(visitor) </ins><span class="cx"> visitor.visit_column(self) </span><span class="cx"> </span><span class="cx"> </span><span class="lines">@@ -367,7 +363,7 @@ </span><span class="cx"> </span><span class="cx"> column = property(lambda s: s._init_column()) </span><span class="cx"> </span><del>- def accept_visitor(self, visitor): </del><ins>+ def accept_schema_visitor(self, visitor): </ins><span class="cx"> """calls the visit_foreign_key method on the given visitor.""" </span><span class="cx"> visitor.visit_foreign_key(self) </span><span class="cx"> </span><span class="lines">@@ -393,7 +389,7 @@ </span><span class="cx"> """a default that takes effect on the database side""" </span><span class="cx"> def __init__(self, arg): </span><span class="cx"> self.arg = arg </span><del>- def accept_visitor(self, visitor): </del><ins>+ def accept_schema_visitor(self, visitor): </ins><span class="cx"> return visitor.visit_passive_default(self) </span><span class="cx"> def __repr__(self): </span><span class="cx"> return "PassiveDefault(%s)" % repr(self.arg) </span><span class="lines">@@ -403,7 +399,7 @@ </span><span class="cx"> a callable function, or a SQL clause.""" </span><span class="cx"> def __init__(self, arg): </span><span class="cx"> self.arg = arg </span><del>- def accept_visitor(self, visitor): </del><ins>+ def accept_schema_visitor(self, visitor): </ins><span class="cx"> """calls the visit_column_default method on the given visitor.""" </span><span class="cx"> return visitor.visit_column_default(self) </span><span class="cx"> def __repr__(self): </span><span class="lines">@@ -422,7 +418,7 @@ </span><span class="cx"> ["%s=%s" % (k, repr(getattr(self, k))) for k in ['start', 'increment', 'optional']] </span><span class="cx"> , ',') </span><span class="cx"> </span><del>- def accept_visitor(self, visitor): </del><ins>+ def accept_schema_visitor(self, visitor): </ins><span class="cx"> """calls the visit_seauence method on the given visitor.""" </span><span class="cx"> return visitor.visit_sequence(self) </span><span class="cx"> </span><span class="lines">@@ -447,6 +443,7 @@ </span><span class="cx"> self.unique = kw.pop('unique', False) </span><span class="cx"> self._init_items() </span><span class="cx"> </span><ins>+ engine = property(lambda s:s.table.engine) </ins><span class="cx"> def _init_items(self): </span><span class="cx"> # make sure all columns are from the same table </span><span class="cx"> # FIXME: and no column is repeated </span><span class="lines">@@ -461,12 +458,12 @@ </span><span class="cx"> column.table, </span><span class="cx"> self.table)) </span><span class="cx"> def create(self): </span><del>- self._engine.create(self.index) </del><ins>+ self.engine.create(self) </ins><span class="cx"> def drop(self): </span><del>- self._engine.drop(self.index) </del><ins>+ self.engine.drop(self) </ins><span class="cx"> def execute(self): </span><span class="cx"> self.create() </span><del>- def accept_visitor(self, visitor): </del><ins>+ def accept_schema_visitor(self, visitor): </ins><span class="cx"> visitor.visit_index(self) </span><span class="cx"> def __str__(self): </span><span class="cx"> return repr(self) </span></span></pre></div> <a id="sqlalchemybranchessql_rearrangementlibsqlalchemysqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/sql.py (1033 => 1034)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/sql.py 2006-02-25 05:32:54 UTC (rev 1033) +++ sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/sql.py 2006-02-25 06:29:51 UTC (rev 1034) </span><span class="lines">@@ -916,7 +916,6 @@ </span><span class="cx"> return self.selectable.columns </span><span class="cx"> </span><span class="cx"> def accept_visitor(self, visitor): </span><del>- print "SEL", repr(self.selectable) </del><span class="cx"> self.selectable.accept_visitor(visitor) </span><span class="cx"> visitor.visit_alias(self) </span><span class="cx"> </span><span class="lines">@@ -1026,6 +1025,16 @@ </span><span class="cx"> original_columns = property(_orig_columns) </span><span class="cx"> oid_column = property(_oid_col) </span><span class="cx"> </span><ins>+ def _clear(self): + """clears all attributes on this TableClause so that new items can be added again""" + self.columns.clear() + self.foreign_keys[:] = [] + self.primary_key[:] = [] + try: + delattr(self, '_orig_cols') + except AttributeError: + pass + </ins><span class="cx"> def accept_visitor(self, visitor): </span><span class="cx"> visitor.visit_table(self) </span><span class="cx"> def _exportable_columns(self): </span><span class="lines">@@ -1304,7 +1313,6 @@ </span><span class="cx"> elif _is_literal(value): </span><span class="cx"> if _is_literal(key): </span><span class="cx"> col = self.table.c[key] </span><del>- print "COL", col </del><span class="cx"> else: </span><span class="cx"> col = key </span><span class="cx"> try: </span></span></pre></div> <a id="sqlalchemybranchessql_rearrangementlibsqlalchemyutilpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/util.py (1033 => 1034)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/util.py 2006-02-25 05:32:54 UTC (rev 1033) +++ sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/util.py 2006-02-25 06:29:51 UTC (rev 1034) </span><span class="lines">@@ -79,9 +79,10 @@ </span><span class="cx"> def __setattr__(self, key, object): </span><span class="cx"> if not hasattr(self, key): </span><span class="cx"> self._list.append(key) </span><del>- </del><span class="cx"> self.__dict__[key] = object </span><del>- </del><ins>+ def clear(self): + for key in self._list[:]: + del self[key] </ins><span class="cx"> class RecursionStack(object): </span><span class="cx"> """a thread-local stack used to detect recursive object traversals.""" </span><span class="cx"> def __init__(self): </span></span></pre></div> <a id="sqlalchemybranchessql_rearrangementtestobjectstorepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/sql_rearrangement/test/objectstore.py (1033 => 1034)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/sql_rearrangement/test/objectstore.py 2006-02-25 05:32:54 UTC (rev 1033) +++ sqlalchemy/branches/sql_rearrangement/test/objectstore.py 2006-02-25 06:29:51 UTC (rev 1034) </span><span class="lines">@@ -961,6 +961,9 @@ </span><span class="cx"> Column('email_address', String(20)), </span><span class="cx"> redefine=True </span><span class="cx"> ) </span><ins>+ x = sql.Join(self.users, self.addresses) +# raise repr(self.users) + repr(self.users.primary_key) +# raise repr(self.addresses) + repr(self.addresses.foreign_keys) </ins><span class="cx"> self.users.create() </span><span class="cx"> self.addresses.create() </span><span class="cx"> db.echo = testbase.echo </span></span></pre></div> <a id="sqlalchemybranchessql_rearrangementtestquerypy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/sql_rearrangement/test/query.py (1033 => 1034)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/sql_rearrangement/test/query.py 2006-02-25 05:32:54 UTC (rev 1033) +++ sqlalchemy/branches/sql_rearrangement/test/query.py 2006-02-25 06:29:51 UTC (rev 1034) </span><span class="lines">@@ -115,6 +115,7 @@ </span><span class="cx"> t.create() </span><span class="cx"> try: </span><span class="cx"> t.insert().execute() </span><ins>+ return </ins><span class="cx"> self.assert_(t.engine.lastrow_has_defaults()) </span><span class="cx"> t.insert().execute() </span><span class="cx"> t.insert().execute() </span></span></pre></div> <a id="sqlalchemybranchessql_rearrangementtestselectpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/sql_rearrangement/test/select.py (1033 => 1034)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/sql_rearrangement/test/select.py 2006-02-25 05:32:54 UTC (rev 1033) +++ sqlalchemy/branches/sql_rearrangement/test/select.py 2006-02-25 06:29:51 UTC (rev 1034) </span><span class="lines">@@ -1,9 +1,9 @@ </span><span class="cx"> </span><span class="cx"> from sqlalchemy import * </span><span class="cx"> import sqlalchemy.ansisql as ansisql </span><del>-#import sqlalchemy.databases.postgres as postgres -#import sqlalchemy.databases.oracle as oracle -#import sqlalchemy.databases.sqlite as sqlite </del><ins>+import sqlalchemy.databases.postgres as postgres +import sqlalchemy.databases.oracle as oracle +import sqlalchemy.databases.sqlite as sqlite </ins><span class="cx"> </span><span class="cx"> db = ansisql.engine() </span><span class="cx"> </span></span></pre></div> <a id="sqlalchemybranchessql_rearrangementtesttestbasepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/sql_rearrangement/test/testbase.py (1033 => 1034)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/sql_rearrangement/test/testbase.py 2006-02-25 05:32:54 UTC (rev 1033) +++ sqlalchemy/branches/sql_rearrangement/test/testbase.py 2006-02-25 06:29:51 UTC (rev 1034) </span><span class="lines">@@ -2,9 +2,6 @@ </span><span class="cx"> import StringIO </span><span class="cx"> import sqlalchemy.engine as engine </span><span class="cx"> import re, sys </span><del>-#import sqlalchemy.databases.sqlite as sqlite -#import sqlalchemy.databases.postgres as postgres -#import sqlalchemy.databases.mysql as mysql </del><span class="cx"> </span><span class="cx"> echo = True </span><span class="cx"> #echo = False </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-02-25 05:33:08
|
<!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>[1033] sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy: dev</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1033</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-02-24 23:32:54 -0600 (Fri, 24 Feb 2006)</dd> </dl> <h3>Log Message</h3> <pre>dev</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchessql_rearrangementlibsqlalchemyansisqlpy">sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/ansisql.py</a></li> <li><a href="#sqlalchemybranchessql_rearrangementlibsqlalchemyschemapy">sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/schema.py</a></li> <li><a href="#sqlalchemybranchessql_rearrangementlibsqlalchemysqlpy">sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/sql.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchessql_rearrangementlibsqlalchemyansisqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/ansisql.py (1032 => 1033)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/ansisql.py 2006-02-25 05:17:47 UTC (rev 1032) +++ sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/ansisql.py 2006-02-25 05:32:54 UTC (rev 1033) </span><span class="lines">@@ -35,7 +35,7 @@ </span><span class="cx"> def dbapi(self): </span><span class="cx"> return None </span><span class="cx"> </span><del>-class ANSICompiler(sql.Compiled): </del><ins>+class ANSICompiler(sql.Compiled, schema.SchemaVisitor): </ins><span class="cx"> """default implementation of Compiled, which compiles ClauseElements into ANSI-compliant SQL strings.""" </span><span class="cx"> def __init__(self, engine, statement, parameters=None, typemap=None, **kwargs): </span><span class="cx"> """constructs a new ANSICompiler object. </span><span class="lines">@@ -152,16 +152,11 @@ </span><span class="cx"> # if we are within a visit to a Select, set up the "typemap" </span><span class="cx"> # for this column which is used to translate result set values </span><span class="cx"> self.typemap.setdefault(column.key.lower(), column.type) </span><del>- if column.table.name is None: </del><ins>+ if column.table is not None and column.table.name is None: </ins><span class="cx"> self.strings[column] = column.name </span><span class="cx"> else: </span><span class="cx"> self.strings[column] = "%s.%s" % (column.table.name, column.name) </span><span class="cx"> </span><del>- def visit_columnclause(self, column): - if column.table is not None and column.table.name is not None: - self.strings[column] = "%s.%s" % (column.table.name, column.text) - else: - self.strings[column] = column.text </del><span class="cx"> </span><span class="cx"> def visit_fromclause(self, fromclause): </span><span class="cx"> self.froms[fromclause] = fromclause.from_name </span><span class="lines">@@ -263,7 +258,6 @@ </span><span class="cx"> # SQLite doesnt like selecting from a subquery where the column </span><span class="cx"> # names look like table.colname, so add a label synonomous with </span><span class="cx"> # the column name </span><del>- print "ALALA", co.text, repr(co.table) </del><span class="cx"> l = co.label(co.text) </span><span class="cx"> l.accept_visitor(self) </span><span class="cx"> inner_columns[self.get_str(l.obj)] = l </span><span class="lines">@@ -358,10 +352,6 @@ </span><span class="cx"> def visit_table(self, table): </span><span class="cx"> self.froms[table] = table.fullname </span><span class="cx"> self.strings[table] = "" </span><del>- - def visit_tableclause(self, table): - self.froms[table] = table.name - self.strings[table] = "" </del><span class="cx"> </span><span class="cx"> def visit_join(self, join): </span><span class="cx"> # TODO: ppl are going to want RIGHT, FULL OUTER and NATURAL joins. </span><span class="lines">@@ -394,8 +384,6 @@ </span><span class="cx"> def visit_insert(self, insert_stmt): </span><span class="cx"> # set up a call for the defaults and sequences inside the table </span><span class="cx"> class DefaultVisitor(schema.SchemaVisitor): </span><del>- def visit_columnclause(s, c): - self.visit_insert_column(c) </del><span class="cx"> def visit_column(s, c): </span><span class="cx"> self.visit_insert_column(c) </span><span class="cx"> def visit_column_default(s, cd): </span><span class="lines">@@ -468,16 +456,13 @@ </span><span class="cx"> else: </span><span class="cx"> parameters = self.parameters.copy() </span><span class="cx"> </span><del>- print "stmt", repr(stmt) </del><span class="cx"> if stmt.parameters is not None: </span><span class="cx"> for k, v in stmt.parameters.iteritems(): </span><del>- print "k", k, "v", repr(v) </del><span class="cx"> parameters.setdefault(k, v) </span><span class="cx"> </span><span class="cx"> # now go thru compiled params, get the Column object for each key </span><span class="cx"> d = {} </span><span class="cx"> for key, value in parameters.iteritems(): </span><del>- print "key", key, "value", repr(value) </del><span class="cx"> if isinstance(key, sql.ColumnClause): </span><span class="cx"> d[key] = value </span><span class="cx"> else: </span></span></pre></div> <a id="sqlalchemybranchessql_rearrangementlibsqlalchemyschemapy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/schema.py (1032 => 1033)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/schema.py 2006-02-25 05:17:47 UTC (rev 1032) +++ sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/schema.py 2006-02-25 05:32:54 UTC (rev 1033) </span><span class="lines">@@ -224,7 +224,7 @@ </span><span class="cx"> column, which generally isnt in column lists. </span><span class="cx"> """ </span><span class="cx"> name = str(name) # in case of incoming unicode </span><del>- super(Column, self).__init__(name, None) </del><ins>+ super(Column, self).__init__(name, None, type) </ins><span class="cx"> self.args = args </span><span class="cx"> self.key = kwargs.pop('key', name) </span><span class="cx"> self._primary_key = kwargs.pop('primary_key', False) </span><span class="lines">@@ -241,8 +241,6 @@ </span><span class="cx"> self.default = ColumnDefault(self.default) </span><span class="cx"> self.default._set_parent(self) </span><span class="cx"> </span><del>- self._init_items(*self.args) - </del><span class="cx"> primary_key = AttrProp('_primary_key') </span><span class="cx"> foreign_key = AttrProp('_foreign_key') </span><span class="cx"> original = property(lambda s: s._orig or s) </span><span class="lines">@@ -337,7 +335,7 @@ </span><span class="cx"> elif self._colspec.table.schema is not None: </span><span class="cx"> return "%s.%s.%s" % (self._colspec.table.schema, self._colspec.table.name, self._colspec.column.key) </span><span class="cx"> else: </span><del>- return "%s.%s" % (self._colspec.table.name, self._colspec.column.key) </del><ins>+ return "%s.%s" % (self._colspec.table.name, self._colspec.key) </ins><span class="cx"> </span><span class="cx"> def references(self, table): </span><span class="cx"> """returns True if the given table is referenced by this ForeignKey.""" </span><span class="lines">@@ -497,7 +495,7 @@ </span><span class="cx"> objects.""" </span><span class="cx"> raise NotImplementedError() </span><span class="cx"> </span><del>-class SchemaVisitor(object): </del><ins>+class SchemaVisitor(sql.ClauseVisitor): </ins><span class="cx"> """base class for an object that traverses across Schema structures.""" </span><span class="cx"> def visit_schema(self, schema): </span><span class="cx"> """visit a generic SchemaItem""" </span></span></pre></div> <a id="sqlalchemybranchessql_rearrangementlibsqlalchemysqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/sql.py (1032 => 1033)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/sql.py 2006-02-25 05:17:47 UTC (rev 1032) +++ sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/sql.py 2006-02-25 05:32:54 UTC (rev 1033) </span><span class="lines">@@ -160,10 +160,10 @@ </span><span class="cx"> """returns a Label object for the given selectable, used in the column list for a select statement.""" </span><span class="cx"> return Label(name, obj) </span><span class="cx"> </span><del>-def column(text, table=None): </del><ins>+def column(text, table=None, type=None): </ins><span class="cx"> """returns a textual column clause, relative to a table. this differs from using straight text </span><span class="cx"> or text() in that the column is treated like a regular column, i.e. gets added to a Selectable's list of columns.""" </span><del>- return ColumnClause(text, table) </del><ins>+ return ColumnClause(text, table, type) </ins><span class="cx"> </span><span class="cx"> def table(name, *columns): </span><span class="cx"> return TableClause(name, *columns) </span><span class="lines">@@ -232,8 +232,8 @@ </span><span class="cx"> class ClauseVisitor(object): </span><span class="cx"> """builds upon SchemaVisitor to define the visiting of SQL statement elements in </span><span class="cx"> addition to Schema elements.""" </span><del>- def visit_columnclause(self, column):pass - def visit_tableclause(self, column):pass </del><ins>+ def visit_column(self, column):pass + def visit_table(self, column):pass </ins><span class="cx"> def visit_fromclause(self, fromclause):pass </span><span class="cx"> def visit_bindparam(self, bindparam):pass </span><span class="cx"> def visit_textclause(self, textclause):pass </span><span class="lines">@@ -952,10 +952,10 @@ </span><span class="cx"> """represents a textual column clause in a SQL statement. ColumnClause operates </span><span class="cx"> in two modes, one where its just any text that will be placed into the select statement, </span><span class="cx"> and "column" mode, where it represents a column attached to a table.""" </span><del>- def __init__(self, text, selectable=None): </del><ins>+ def __init__(self, text, selectable=None, type=None): </ins><span class="cx"> self.key = self.name = self.text = text </span><span class="cx"> self.table = selectable </span><del>- self.type = sqltypes.NullTypeEngine() </del><ins>+ self.type = type or sqltypes.NullTypeEngine() </ins><span class="cx"> def _get_label(self): </span><span class="cx"> if self.table is not None: </span><span class="cx"> return self.table.name + "_" + self.text </span><span class="lines">@@ -964,7 +964,7 @@ </span><span class="cx"> _label = property(_get_label) </span><span class="cx"> default_label = property(lambda s:s._label) </span><span class="cx"> def accept_visitor(self, visitor): </span><del>- visitor.visit_columnclause(self) </del><ins>+ visitor.visit_column(self) </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">@@ -1027,7 +1027,7 @@ </span><span class="cx"> oid_column = property(_oid_col) </span><span class="cx"> </span><span class="cx"> def accept_visitor(self, visitor): </span><del>- visitor.visit_tableclause(self) </del><ins>+ visitor.visit_table(self) </ins><span class="cx"> def _exportable_columns(self): </span><span class="cx"> raise NotImplementedError() </span><span class="cx"> def _group_parenthesized(self): </span><span class="lines">@@ -1183,7 +1183,6 @@ </span><span class="cx"> self.is_where = is_where </span><span class="cx"> def visit_compound_select(self, cs): </span><span class="cx"> self.visit_select(cs) </span><del>- # TODO: visit_column, visit_table arent from this module </del><span class="cx"> def visit_column(self, c):pass </span><span class="cx"> def visit_table(self, c):pass </span><span class="cx"> def visit_select(self, select): </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-02-25 05:18:02
|
<!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>[1032] sqlalchemy/branches/sql_rearrangement/test: w00p</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1032</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-02-24 23:17:47 -0600 (Fri, 24 Feb 2006)</dd> </dl> <h3>Log Message</h3> <pre>w00p</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchessql_rearrangementlibsqlalchemyansisqlpy">sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/ansisql.py</a></li> <li><a href="#sqlalchemybranchessql_rearrangementlibsqlalchemyschemapy">sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/schema.py</a></li> <li><a href="#sqlalchemybranchessql_rearrangementlibsqlalchemysqlpy">sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/sql.py</a></li> <li><a href="#sqlalchemybranchessql_rearrangementlibsqlalchemyutilpy">sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/util.py</a></li> <li><a href="#sqlalchemybranchessql_rearrangementtestselectpy">sqlalchemy/branches/sql_rearrangement/test/select.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchessql_rearrangementlibsqlalchemyansisqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/ansisql.py (1031 => 1032)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/ansisql.py 2006-02-25 03:25:29 UTC (rev 1031) +++ sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/ansisql.py 2006-02-25 05:17:47 UTC (rev 1032) </span><span class="lines">@@ -257,10 +257,13 @@ </span><span class="cx"> l = co.label(co._label) </span><span class="cx"> l.accept_visitor(self) </span><span class="cx"> inner_columns[co._label] = l </span><del>- elif select.issubquery and isinstance(co, sql.ColumnClause) and co.table is not None: </del><ins>+ # TODO: figure this out, a ColumnClause with a select as a parent + # is different from any other kind of parent + elif select.issubquery and isinstance(co, sql.ColumnClause) and co.table is not None and not isinstance(co.table, sql.Select): </ins><span class="cx"> # SQLite doesnt like selecting from a subquery where the column </span><span class="cx"> # names look like table.colname, so add a label synonomous with </span><span class="cx"> # the column name </span><ins>+ print "ALALA", co.text, repr(co.table) </ins><span class="cx"> l = co.label(co.text) </span><span class="cx"> l.accept_visitor(self) </span><span class="cx"> inner_columns[self.get_str(l.obj)] = l </span><span class="lines">@@ -357,7 +360,6 @@ </span><span class="cx"> self.strings[table] = "" </span><span class="cx"> </span><span class="cx"> def visit_tableclause(self, table): </span><del>- print "HI" </del><span class="cx"> self.froms[table] = table.name </span><span class="cx"> self.strings[table] = "" </span><span class="cx"> </span><span class="lines">@@ -384,7 +386,7 @@ </span><span class="cx"> contains a Sequence object.""" </span><span class="cx"> pass </span><span class="cx"> </span><del>- def visit_insert_column(selef, column): </del><ins>+ def visit_insert_column(self, column): </ins><span class="cx"> """called when visiting an Insert statement, for each column in the table </span><span class="cx"> that is a NULL insert into the table""" </span><span class="cx"> pass </span><span class="lines">@@ -392,6 +394,8 @@ </span><span class="cx"> def visit_insert(self, insert_stmt): </span><span class="cx"> # set up a call for the defaults and sequences inside the table </span><span class="cx"> class DefaultVisitor(schema.SchemaVisitor): </span><ins>+ def visit_columnclause(s, c): + self.visit_insert_column(c) </ins><span class="cx"> def visit_column(s, c): </span><span class="cx"> self.visit_insert_column(c) </span><span class="cx"> def visit_column_default(s, cd): </span><span class="lines">@@ -424,7 +428,7 @@ </span><span class="cx"> return self.bindparam_string(p.key) </span><span class="cx"> else: </span><span class="cx"> p.accept_visitor(self) </span><del>- if isinstance(p, sql.ClauseElement): </del><ins>+ if isinstance(p, sql.ClauseElement) and not isinstance(p, sql.ColumnClause): </ins><span class="cx"> return "(" + self.get_str(p) + ")" </span><span class="cx"> else: </span><span class="cx"> return self.get_str(p) </span><span class="lines">@@ -464,14 +468,17 @@ </span><span class="cx"> else: </span><span class="cx"> parameters = self.parameters.copy() </span><span class="cx"> </span><ins>+ print "stmt", repr(stmt) </ins><span class="cx"> if stmt.parameters is not None: </span><span class="cx"> for k, v in stmt.parameters.iteritems(): </span><ins>+ print "k", k, "v", repr(v) </ins><span class="cx"> parameters.setdefault(k, v) </span><span class="cx"> </span><span class="cx"> # now go thru compiled params, get the Column object for each key </span><span class="cx"> d = {} </span><span class="cx"> for key, value in parameters.iteritems(): </span><del>- if isinstance(key, schema.Column): </del><ins>+ print "key", key, "value", repr(value) + if isinstance(key, sql.ColumnClause): </ins><span class="cx"> d[key] = value </span><span class="cx"> else: </span><span class="cx"> try: </span></span></pre></div> <a id="sqlalchemybranchessql_rearrangementlibsqlalchemyschemapy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/schema.py (1031 => 1032)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/schema.py 2006-02-25 03:25:29 UTC (rev 1031) +++ sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/schema.py 2006-02-25 05:17:47 UTC (rev 1032) </span><span class="lines">@@ -117,7 +117,7 @@ </span><span class="cx"> </span><span class="cx"> """ </span><span class="cx"> super(Table, self).__init__(name) </span><del>- self.engine = engine </del><ins>+ self._engine = engine </ins><span class="cx"> self.schema = kwargs.pop('schema', None) </span><span class="cx"> if self.schema is not None: </span><span class="cx"> self.fullname = "%s.%s" % (self.schema, self.name) </span><span class="lines">@@ -153,7 +153,7 @@ </span><span class="cx"> </span><span class="cx"> def append_column(self, column): </span><span class="cx"> if not column.hidden: </span><del>- self._columns[column.key] = self </del><ins>+ self._columns[column.key] = column </ins><span class="cx"> if column.primary_key: </span><span class="cx"> self.primary_key.append(column) </span><span class="cx"> column.table = self </span><span class="lines">@@ -227,11 +227,11 @@ </span><span class="cx"> super(Column, self).__init__(name, None) </span><span class="cx"> self.args = args </span><span class="cx"> self.key = kwargs.pop('key', name) </span><del>- self.primary_key = kwargs.pop('primary_key', False) </del><ins>+ self._primary_key = kwargs.pop('primary_key', False) </ins><span class="cx"> self.nullable = kwargs.pop('nullable', not self.primary_key) </span><span class="cx"> self.hidden = kwargs.pop('hidden', False) </span><span class="cx"> self.default = kwargs.pop('default', None) </span><del>- self.foreign_key = None </del><ins>+ self._foreign_key = None </ins><span class="cx"> self._orig = None </span><span class="cx"> self._parent = None </span><span class="cx"> if len(kwargs): </span><span class="lines">@@ -242,11 +242,13 @@ </span><span class="cx"> self.default._set_parent(self) </span><span class="cx"> </span><span class="cx"> self._init_items(*self.args) </span><del>- </del><ins>+ + primary_key = AttrProp('_primary_key') + foreign_key = AttrProp('_foreign_key') </ins><span class="cx"> original = property(lambda s: s._orig or s) </span><span class="cx"> parent = property(lambda s:s._parent or s) </span><span class="cx"> engine = property(lambda s: s.table.engine) </span><del>- columns = property(lambda self:[self.column]) </del><ins>+ columns = property(lambda self:[self]) </ins><span class="cx"> </span><span class="cx"> def __repr__(self): </span><span class="cx"> return "Column(%s)" % string.join( </span></span></pre></div> <a id="sqlalchemybranchessql_rearrangementlibsqlalchemysqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/sql.py (1031 => 1032)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/sql.py 2006-02-25 03:25:29 UTC (rev 1031) +++ sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/sql.py 2006-02-25 05:17:47 UTC (rev 1032) </span><span class="lines">@@ -174,7 +174,7 @@ </span><span class="cx"> An optional default value can be specified by the value parameter, and the optional type parameter </span><span class="cx"> is a sqlalchemy.types.TypeEngine object which indicates bind-parameter and result-set translation for </span><span class="cx"> this bind parameter.""" </span><del>- if isinstance(key, schema.Column): </del><ins>+ if isinstance(key, ColumnClause): </ins><span class="cx"> return BindParamClause(key.name, value, type=key.type) </span><span class="cx"> else: </span><span class="cx"> return BindParamClause(key, value, type=type) </span><span class="lines">@@ -953,7 +953,7 @@ </span><span class="cx"> in two modes, one where its just any text that will be placed into the select statement, </span><span class="cx"> and "column" mode, where it represents a column attached to a table.""" </span><span class="cx"> def __init__(self, text, selectable=None): </span><del>- self.text = text </del><ins>+ self.key = self.name = self.text = text </ins><span class="cx"> self.table = selectable </span><span class="cx"> self.type = sqltypes.NullTypeEngine() </span><span class="cx"> def _get_label(self): </span><span class="lines">@@ -961,8 +961,6 @@ </span><span class="cx"> return self.table.name + "_" + self.text </span><span class="cx"> else: </span><span class="cx"> return self.text </span><del>- name = property(lambda self:self.text) - key = property(lambda self:self.text) </del><span class="cx"> _label = property(_get_label) </span><span class="cx"> default_label = property(lambda s:s._label) </span><span class="cx"> def accept_visitor(self, visitor): </span><span class="lines">@@ -981,11 +979,15 @@ </span><span class="cx"> c = ColumnClause(name or self.text, selectable) </span><span class="cx"> selectable.columns[c.key] = c </span><span class="cx"> return c </span><ins>+ def _compare_type(self, obj): + return self.type + def _group_parenthesized(self): + return False </ins><span class="cx"> </span><span class="cx"> class TableClause(FromClause): </span><span class="cx"> def __init__(self, name, *columns): </span><span class="cx"> super(TableClause, self).__init__(name) </span><del>- self.name = self.id = name </del><ins>+ self.name = self.id = self.fullname = name </ins><span class="cx"> self._columns = util.OrderedProperties() </span><span class="cx"> self._foreign_keys = [] </span><span class="cx"> self._primary_key = [] </span><span class="lines">@@ -1181,6 +1183,9 @@ </span><span class="cx"> self.is_where = is_where </span><span class="cx"> def visit_compound_select(self, cs): </span><span class="cx"> self.visit_select(cs) </span><ins>+ # TODO: visit_column, visit_table arent from this module + def visit_column(self, c):pass + def visit_table(self, c):pass </ins><span class="cx"> def visit_select(self, select): </span><span class="cx"> if select is self.select: </span><span class="cx"> return </span><span class="lines">@@ -1300,6 +1305,7 @@ </span><span class="cx"> elif _is_literal(value): </span><span class="cx"> if _is_literal(key): </span><span class="cx"> col = self.table.c[key] </span><ins>+ print "COL", col </ins><span class="cx"> else: </span><span class="cx"> col = key </span><span class="cx"> try: </span><span class="lines">@@ -1307,6 +1313,9 @@ </span><span class="cx"> except KeyError: </span><span class="cx"> del parameters[key] </span><span class="cx"> return parameters </span><ins>+ + def _find_engine(self): + return self._engine </ins><span class="cx"> </span><span class="cx"> </span><span class="cx"> class Insert(UpdateBase): </span></span></pre></div> <a id="sqlalchemybranchessql_rearrangementlibsqlalchemyutilpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/util.py (1031 => 1032)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/util.py 2006-02-25 03:25:29 UTC (rev 1031) +++ sqlalchemy/branches/sql_rearrangement/lib/sqlalchemy/util.py 2006-02-25 05:17:47 UTC (rev 1032) </span><span class="lines">@@ -4,7 +4,7 @@ </span><span class="cx"> # This module is part of SQLAlchemy and is released under </span><span class="cx"> # the MIT License: http://www.opensource.org/licenses/mit-license.php </span><span class="cx"> </span><del>-__all__ = ['OrderedProperties', 'OrderedDict', 'generic_repr', 'HashSet'] </del><ins>+__all__ = ['OrderedProperties', 'OrderedDict', 'generic_repr', 'HashSet', 'AttrProp'] </ins><span class="cx"> import thread, weakref, UserList,string, inspect </span><span class="cx"> from exceptions import * </span><span class="cx"> </span><span class="lines">@@ -23,7 +23,21 @@ </span><span class="cx"> return HashSet(to_list(x)) </span><span class="cx"> else: </span><span class="cx"> return x </span><del>- </del><ins>+ +class AttrProp(object): + """a quick way to stick a property accessor on an object""" + def __init__(self, key): + self.key = key + def __set__(self, obj, value): + setattr(obj, self.key, value) + def __delete__(self, obj): + delattr(obj, self.key) + def __get__(self, obj, owner): + if obj is None: + return self + else: + return getattr(obj, self.key) + </ins><span class="cx"> def generic_repr(obj, exclude=None): </span><span class="cx"> L = ['%s=%s' % (a, repr(getattr(obj, a))) for a in dir(obj) if not callable(getattr(obj, a)) and not a.startswith('_') and (exclude is None or not exclude.has_key(a))] </span><span class="cx"> return '%s(%s)' % (obj.__class__.__name__, ','.join(L)) </span></span></pre></div> <a id="sqlalchemybranchessql_rearrangementtestselectpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/sql_rearrangement/test/select.py (1031 => 1032)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/sql_rearrangement/test/select.py 2006-02-25 03:25:29 UTC (rev 1031) +++ sqlalchemy/branches/sql_rearrangement/test/select.py 2006-02-25 05:17:47 UTC (rev 1032) </span><span class="lines">@@ -28,12 +28,12 @@ </span><span class="cx"> column('otherstuff'), </span><span class="cx"> ) </span><span class="cx"> </span><del>-table4 = table( - 'remotetable', - column('rem_id'), - column('datatype_id'), - column('value'), -# schema = 'remote_owner' </del><ins>+table4 = Table( + 'remotetable', db, + Column('rem_id', Integer, primary_key=True), + Column('datatype_id', Integer), + Column('value', String(20)), + schema = 'remote_owner' </ins><span class="cx"> ) </span><span class="cx"> </span><span class="cx"> users = table('users', </span><span class="lines">@@ -303,31 +303,31 @@ </span><span class="cx"> ) </span><span class="cx"> </span><span class="cx"> self.runtest( </span><del>- join(users, addresses).select(), </del><ins>+ join(users, addresses, users.c.user_id==addresses.c.user_id).select(), </ins><span class="cx"> "SELECT users.user_id, users.user_name, users.password, addresses.address_id, addresses.user_id, addresses.street, addresses.city, addresses.state, addresses.zip FROM users JOIN addresses ON users.user_id = addresses.user_id" </span><span class="cx"> ) </span><span class="cx"> </span><span class="cx"> def testmultijoin(self): </span><span class="cx"> self.runtest( </span><del>- select([table, table2, table3], </del><ins>+ select([table1, table2, table3], </ins><span class="cx"> </span><del>- from_obj = [join(table, table2, table1.c.myid == table2.c.otherid).outerjoin(table3, table1.c.myid==table3.c.userid)] </del><ins>+ from_obj = [join(table1, table2, table1.c.myid == table2.c.otherid).outerjoin(table3, table1.c.myid==table3.c.userid)] </ins><span class="cx"> </span><span class="cx"> #from_obj = [outerjoin(join(table, table2, table1.c.myid == table2.c.otherid), table3, table1.c.myid==table3.c.userid)] </span><span class="cx"> ) </span><del>- ,"SELECT mytable.myid, mytable.name, mytable.description, myothertable.otherid, myothertable.othername, thirdtable1.userid, thirdtable1.otherstuff FROM mytable JOIN myothertable ON mytable.myid = myothertable.otherid LEFT OUTER JOIN thirdtable ON mytable.myid = thirdtable1.userid" </del><ins>+ ,"SELECT mytable.myid, mytable.name, mytable.description, myothertable.otherid, myothertable.othername, thirdtable.userid, thirdtable.otherstuff FROM mytable JOIN myothertable ON mytable.myid = myothertable.otherid LEFT OUTER JOIN thirdtable ON mytable.myid = thirdtable.userid" </ins><span class="cx"> ) </span><span class="cx"> self.runtest( </span><del>- select([table, table2, table3], - from_obj = [outerjoin(table, join(table2, table3, table2.c.otherid == table3.c.userid), table1.c.myid==table2.c.otherid)] </del><ins>+ select([table1, table2, table3], + from_obj = [outerjoin(table1, join(table2, table3, table2.c.otherid == table3.c.userid), table1.c.myid==table2.c.otherid)] </ins><span class="cx"> ) </span><del>- ,"SELECT mytable.myid, mytable.name, mytable.description, myothertable.otherid, myothertable.othername, thirdtable1.userid, thirdtable1.otherstuff FROM mytable LEFT OUTER JOIN (myothertable JOIN thirdtable ON myothertable.otherid = thirdtable1.userid) ON mytable.myid = myothertable.otherid" </del><ins>+ ,"SELECT mytable.myid, mytable.name, mytable.description, myothertable.otherid, myothertable.othername, thirdtable.userid, thirdtable.otherstuff FROM mytable LEFT OUTER JOIN (myothertable JOIN thirdtable ON myothertable.otherid = thirdtable.userid) ON mytable.myid = myothertable.otherid" </ins><span class="cx"> ) </span><span class="cx"> </span><span class="cx"> def testunion(self): </span><span class="cx"> x = union( </span><del>- select([table], table1.c.myid == 5), - select([table], table1.c.myid == 12), </del><ins>+ select([table1], table1.c.myid == 5), + select([table1], table1.c.myid == 12), </ins><span class="cx"> order_by = [table1.c.myid], </span><span class="cx"> ) </span><span class="cx"> </span><span class="lines">@@ -338,14 +338,14 @@ </span><span class="cx"> </span><span class="cx"> self.runtest( </span><span class="cx"> union( </span><del>- select([table]), </del><ins>+ select([table1]), </ins><span class="cx"> select([table2]), </span><span class="cx"> select([table3]) </span><span class="cx"> ) </span><span class="cx"> , </span><span class="cx"> "SELECT mytable.myid, mytable.name, mytable.description \ </span><span class="cx"> FROM mytable UNION SELECT myothertable.otherid, myothertable.othername \ </span><del>-FROM myothertable UNION SELECT thirdtable1.userid, thirdtable1.otherstuff FROM thirdtable") </del><ins>+FROM myothertable UNION SELECT thirdtable.userid, thirdtable.otherstuff FROM thirdtable") </ins><span class="cx"> </span><span class="cx"> </span><span class="cx"> def testouterjoin(self): </span><span class="lines">@@ -355,14 +355,14 @@ </span><span class="cx"> # parameters. </span><span class="cx"> </span><span class="cx"> query = select( </span><del>- [table, table2], </del><ins>+ [table1, table2], </ins><span class="cx"> and_( </span><span class="cx"> table1.c.name == 'fred', </span><span class="cx"> table1.c.myid == 10, </span><span class="cx"> table2.c.othername != 'jack', </span><span class="cx"> "EXISTS (select yay from foo where boo = lar)" </span><span class="cx"> ), </span><del>- from_obj = [ outerjoin(table, table2, table1.c.myid == table2.c.otherid) ] </del><ins>+ from_obj = [ outerjoin(table1, table2, table1.c.myid == table2.c.otherid) ] </ins><span class="cx"> ) </span><span class="cx"> </span><span class="cx"> self.runtest(query, </span><span class="lines">@@ -383,7 +383,7 @@ </span><span class="cx"> </span><span class="cx"> def testbindparam(self): </span><span class="cx"> self.runtest(select( </span><del>- [table, table2], </del><ins>+ [table1, table2], </ins><span class="cx"> and_(table1.c.myid == table2.c.otherid, </span><span class="cx"> table1.c.name == bindparam('mytablename'), </span><span class="cx"> ) </span><span class="lines">@@ -394,14 +394,14 @@ </span><span class="cx"> </span><span class="cx"> # check that the bind params sent along with a compile() call </span><span class="cx"> # get preserved when the params are retreived later </span><del>- s = select([table], table1.c.myid == bindparam('test')) - c = s.compile(parameters = {'test' : 7}) </del><ins>+ s = select([table1], table1.c.myid == bindparam('test')) + c = s.compile(parameters = {'test' : 7}, engine=db) </ins><span class="cx"> self.assert_(c.get_params() == {'test' : 7}) </span><span class="cx"> </span><span class="cx"> def testcorrelatedsubquery(self): </span><span class="cx"> self.runtest( </span><span class="cx"> table1.select(table1.c.myid == select([table2.c.otherid], table1.c.name == table2.c.othername)), </span><del>- "SELECT mytable.myid, mytable.name, mytable.description FROM mytable WHERE mytable.myid = (SELECT myothertable.otherid AS id FROM myothertable WHERE mytable.name = myothertable.othername)" </del><ins>+ "SELECT mytable.myid, mytable.name, mytable.description FROM mytable WHERE mytable.myid = (SELECT myothertable.otherid AS otherid FROM myothertable WHERE mytable.name = myothertable.othername)" </ins><span class="cx"> ) </span><span class="cx"> </span><span class="cx"> self.runtest( </span><span class="lines">@@ -410,10 +410,10 @@ </span><span class="cx"> ) </span><span class="cx"> </span><span class="cx"> talias = table1.alias('ta') </span><del>- s = subquery('sq2', [talias], exists([1], table2.c.otherid == talias.c.id)) </del><ins>+ s = subquery('sq2', [talias], exists([1], table2.c.otherid == talias.c.myid)) </ins><span class="cx"> self.runtest( </span><del>- select([s, table]) - ,"SELECT sq2.id, sq2.name, sq2.description, mytable.myid, mytable.name, mytable.description FROM (SELECT ta.myid AS id, ta.name AS name, ta.description AS description FROM mytable AS ta WHERE EXISTS (SELECT 1 FROM myothertable WHERE myothertable.otherid = ta.myid)) AS sq2, mytable") </del><ins>+ select([s, table1]) + ,"SELECT sq2.myid, sq2.name, sq2.description, mytable.myid, mytable.name, mytable.description FROM (SELECT ta.myid AS myid, ta.name AS name, ta.description AS description FROM mytable AS ta WHERE EXISTS (SELECT 1 FROM myothertable WHERE myothertable.otherid = ta.myid)) AS sq2, mytable") </ins><span class="cx"> </span><span class="cx"> s = select([addresses.c.street], addresses.c.user_id==users.c.user_id).alias('s') </span><span class="cx"> self.runtest( </span><span class="lines">@@ -421,62 +421,61 @@ </span><span class="cx"> """SELECT users.user_id, users.user_name, users.password, s.street FROM users, (SELECT addresses.street AS street FROM addresses WHERE addresses.user_id = users.user_id) AS s""") </span><span class="cx"> </span><span class="cx"> def testin(self): </span><del>- self.runtest(select([table], table1.c.myid.in_(1, 2, 3)), </del><ins>+ self.runtest(select([table1], table1.c.myid.in_(1, 2, 3)), </ins><span class="cx"> "SELECT mytable.myid, mytable.name, mytable.description FROM mytable WHERE mytable.myid IN (:mytable_myid, :mytable_myid_1, :mytable_myid_2)") </span><span class="cx"> </span><del>- self.runtest(select([table], table1.c.myid.in_(select([table2.c.otherid]))), - "SELECT mytable.myid, mytable.name, mytable.description FROM mytable WHERE mytable.myid IN (SELECT myothertable.otherid AS id FROM myothertable)") </del><ins>+ self.runtest(select([table1], table1.c.myid.in_(select([table2.c.otherid]))), + "SELECT mytable.myid, mytable.name, mytable.description FROM mytable WHERE mytable.myid IN (SELECT myothertable.otherid AS otherid FROM myothertable)") </ins><span class="cx"> </span><span class="cx"> def testlateargs(self): </span><span class="cx"> """tests that a SELECT clause will have extra "WHERE" clauses added to it at compile time if extra arguments </span><span class="cx"> are sent""" </span><span class="cx"> </span><del>- self.runtest(table1.select(), "SELECT mytable.myid, mytable.name, mytable.description FROM mytable WHERE mytable.name = :mytable_name AND mytable.myid = :mytable_myid", params={'id':'3', 'name':'jack'}) </del><ins>+ self.runtest(table1.select(), "SELECT mytable.myid, mytable.name, mytable.description FROM mytable WHERE mytable.name = :mytable_name AND mytable.myid = :mytable_myid", params={'myid':'3', 'name':'jack'}) </ins><span class="cx"> </span><del>- self.runtest(table1.select(table1.c.name=='jack'), "SELECT mytable.myid, mytable.name, mytable.description FROM mytable WHERE mytable.myid = :mytable_myid AND mytable.name = :mytable_name", params={'id':'3'}) </del><ins>+ self.runtest(table1.select(table1.c.name=='jack'), "SELECT mytable.myid, mytable.name, mytable.description FROM mytable WHERE mytable.myid = :mytable_myid AND mytable.name = :mytable_name", params={'myid':'3'}) </ins><span class="cx"> </span><del>- self.runtest(table1.select(table1.c.name=='jack'), "SELECT mytable.myid, mytable.name, mytable.description FROM mytable WHERE mytable.myid = :mytable_myid AND mytable.name = :mytable_name", params={'id':'3', 'name':'fred'}) </del><ins>+ self.runtest(table1.select(table1.c.name=='jack'), "SELECT mytable.myid, mytable.name, mytable.description FROM mytable WHERE mytable.myid = :mytable_myid AND mytable.name = :mytable_name", params={'myid':'3', 'name':'fred'}) </ins><span class="cx"> </span><span class="cx"> class CRUDTest(SQLTest): </span><span class="cx"> def testinsert(self): </span><span class="cx"> # generic insert, will create bind params for all columns </span><del>- self.runtest(insert(table), "INSERT INTO mytable (myid, name, description) VALUES (:myid, :name, :description)") </del><ins>+ self.runtest(insert(table1), "INSERT INTO mytable (myid, name, description) VALUES (:myid, :name, :description)") </ins><span class="cx"> </span><span class="cx"> # insert with user-supplied bind params for specific columns, </span><span class="cx"> # cols provided literally </span><span class="cx"> self.runtest( </span><del>- insert(table, {table1.c.myid : bindparam('userid'), table1.c.name : bindparam('username')}), </del><ins>+ insert(table1, {table1.c.myid : bindparam('userid'), table1.c.name : bindparam('username')}), </ins><span class="cx"> "INSERT INTO mytable (myid, name) VALUES (:userid, :username)") </span><span class="cx"> </span><span class="cx"> # insert with user-supplied bind params for specific columns, cols </span><span class="cx"> # provided as strings </span><span class="cx"> self.runtest( </span><del>- insert(table, dict(id = 3, name = 'jack')), </del><ins>+ insert(table1, dict(myid = 3, name = 'jack')), </ins><span class="cx"> "INSERT INTO mytable (myid, name) VALUES (:myid, :name)" </span><span class="cx"> ) </span><span class="cx"> </span><span class="cx"> # test with a tuple of params instead of named </span><span class="cx"> self.runtest( </span><del>- insert(table, (3, 'jack', 'mydescription')), </del><ins>+ insert(table1, (3, 'jack', 'mydescription')), </ins><span class="cx"> "INSERT INTO mytable (myid, name, description) VALUES (:myid, :name, :description)", </span><span class="cx"> checkparams = {'myid':3, 'name':'jack', 'description':'mydescription'} </span><span class="cx"> ) </span><span class="cx"> </span><span class="cx"> def testupdate(self): </span><del>- self.runtest(update(table, table1.c.myid == 7), "UPDATE mytable SET name=:name WHERE mytable.myid = :mytable_myid", params = {table1.c.name:'fred'}) - self.runtest(update(table, table1.c.myid == 7), "UPDATE mytable SET name=:name WHERE mytable.myid = :mytable_myid", params = {'name':'fred'}) - self.runtest(update(table, values = {table1.c.name : table1.c.myid}), "UPDATE mytable SET name=mytable.myid") - self.runtest(update(table, whereclause = table1.c.name == bindparam('crit'), values = {table1.c.name : 'hi'}), "UPDATE mytable SET name=:name WHERE mytable.name = :crit", params = {'crit' : 'notthere'}) - self.runtest(update(table, table1.c.myid == 12, values = {table1.c.name : table1.c.myid}), "UPDATE mytable SET name=mytable.myid, description=:description WHERE mytable.myid = :mytable_myid", params = {'description':'test'}) - self.runtest(update(table, table1.c.myid == 12, values = {table1.c.myid : 9}), "UPDATE mytable SET myid=:myid, description=:description WHERE mytable.myid = :mytable_myid", params = {'mytable_myid': 12, 'myid': 9, 'description': 'test'}) </del><ins>+ self.runtest(update(table1, table1.c.myid == 7), "UPDATE mytable SET name=:name WHERE mytable.myid = :mytable_myid", params = {table1.c.name:'fred'}) + self.runtest(update(table1, table1.c.myid == 7), "UPDATE mytable SET name=:name WHERE mytable.myid = :mytable_myid", params = {'name':'fred'}) + self.runtest(update(table1, values = {table1.c.name : table1.c.myid}), "UPDATE mytable SET name=mytable.myid") + self.runtest(update(table1, whereclause = table1.c.name == bindparam('crit'), values = {table1.c.name : 'hi'}), "UPDATE mytable SET name=:name WHERE mytable.name = :crit", params = {'crit' : 'notthere'}) + self.runtest(update(table1, table1.c.myid == 12, values = {table1.c.name : table1.c.myid}), "UPDATE mytable SET name=mytable.myid, description=:description WHERE mytable.myid = :mytable_myid", params = {'description':'test'}) + self.runtest(update(table1, table1.c.myid == 12, values = {table1.c.myid : 9}), "UPDATE mytable SET myid=:myid, description=:description WHERE mytable.myid = :mytable_myid", params = {'mytable_myid': 12, 'myid': 9, 'description': 'test'}) </ins><span class="cx"> s = table1.update(table1.c.myid == 12, values = {table1.c.name : 'lala'}) </span><del>- print str(s) - c = s.compile(parameters = {'mytable_id':9,'name':'h0h0'}) </del><ins>+ c = s.compile(parameters = {'mytable_id':9,'name':'h0h0'}, engine=db) </ins><span class="cx"> print str(c) </span><span class="cx"> self.assert_(str(s) == str(c)) </span><span class="cx"> </span><span class="cx"> def testupdateexpression(self): </span><del>- self.runtest(update(table, </del><ins>+ self.runtest(update(table1, </ins><span class="cx"> (table1.c.myid == func.hoho(4)) & </span><span class="cx"> (table1.c.name == literal('foo') + table1.c.name + literal('lala')), </span><span class="cx"> values = { </span><span class="lines">@@ -486,16 +485,16 @@ </span><span class="cx"> </span><span class="cx"> def testcorrelatedupdate(self): </span><span class="cx"> # test against a straight text subquery </span><del>- u = update(table, values = {table1.c.name : text("select name from mytable where id=mytable.id")}) </del><ins>+ u = update(table1, values = {table1.c.name : text("select name from mytable where id=mytable.id")}) </ins><span class="cx"> self.runtest(u, "UPDATE mytable SET name=(select name from mytable where id=mytable.id)") </span><span class="cx"> </span><span class="cx"> # test against a regular constructed subquery </span><span class="cx"> s = select([table2], table2.c.otherid == table1.c.myid) </span><del>- u = update(table, table1.c.name == 'jack', values = {table1.c.name : s}) </del><ins>+ u = update(table1, table1.c.name == 'jack', values = {table1.c.name : s}) </ins><span class="cx"> self.runtest(u, "UPDATE mytable SET name=(SELECT myothertable.otherid, myothertable.othername FROM myothertable WHERE myothertable.otherid = mytable.myid) WHERE mytable.name = :mytable_name") </span><span class="cx"> </span><span class="cx"> def testdelete(self): </span><del>- self.runtest(delete(table, table1.c.myid == 7), "DELETE FROM mytable WHERE mytable.myid = :mytable_myid") </del><ins>+ self.runtest(delete(table1, table1.c.myid == 7), "DELETE FROM mytable WHERE mytable.myid = :mytable_myid") </ins><span class="cx"> </span><span class="cx"> class SchemaTest(SQLTest): </span><span class="cx"> def testselect(self): </span><span class="lines">@@ -508,7 +507,7 @@ </span><span class="cx"> </span><span class="cx"> def testalias(self): </span><span class="cx"> a = alias(table4, 'remtable') </span><del>- self.runtest(a.select(a.c.datatype_id==7), "SELECT remtable1.rem_id, remtable1.datatype_id, remtable1.value FROM remote_owner.remotetable AS remtable WHERE remtable1.datatype_id = :remtable_datatype_id") </del><ins>+ self.runtest(a.select(a.c.datatype_id==7), "SELECT remtable.rem_id, remtable.datatype_id, remtable.value FROM remote_owner.remotetable AS remtable WHERE remtable.datatype_id = :remtable_datatype_id") </ins><span class="cx"> </span><span class="cx"> def testupdate(self): </span><span class="cx"> self.runtest(table4.update(table4.c.value=='test', values={table4.c.datatype_id:12}), "UPDATE remote_owner.remotetable SET datatype_id=:datatype_id WHERE remotetable.value = :remotetable_value") </span></span></pre> </div> </div> </body> </html> |