sqlalchemy-commits Mailing List for SQLAlchemy (Page 374)
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
|
<!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>[1107] sqlalchemy/trunk/examples: added backref() function, allows the creation of a backref where you also send keyword arguments that will be placed on the relation</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1107</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-03-06 21:14:08 -0600 (Mon, 06 Mar 2006)</dd> </dl> <h3>Log Message</h3> <pre>added backref() function, allows the creation of a backref where you also send keyword arguments that will be placed on the relation</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunklibsqlalchemymapping__init__py">sqlalchemy/trunk/lib/sqlalchemy/mapping/__init__.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemymappingpropertiespy">sqlalchemy/trunk/lib/sqlalchemy/mapping/properties.py</a></li> </ul> <h3>Added Paths</h3> <ul> <li>sqlalchemy/trunk/examples/backref/</li> <li><a href="#sqlalchemytrunkexamplesbackrefbackref_treepy">sqlalchemy/trunk/examples/backref/backref_tree.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunkexamplesbackrefbackref_treepy"></a> <div class="addfile"><h4>Added: sqlalchemy/trunk/examples/backref/backref_tree.py (1106 => 1107)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/examples/backref/backref_tree.py 2006-03-06 23:15:47 UTC (rev 1106) +++ sqlalchemy/trunk/examples/backref/backref_tree.py 2006-03-07 03:14:08 UTC (rev 1107) </span><span class="lines">@@ -0,0 +1,41 @@ </span><ins>+from sqlalchemy import * +import sqlalchemy.attributes as attributes + +engine = create_engine('sqlite://', echo=True) + +class Tree(object): + def __init__(self, name='', father=None): + self.name = name + self.father = father + def __str__(self): + return '<TreeNode: %s>' % self.name + def __repr__(self): + return self.__str__() + +table = Table('tree', engine, + Column('id', Integer, primary_key=True), + Column('name', String(64), nullable=False), + Column('father_id', Integer, ForeignKey('tree.id'), nullable=True),) + +assign_mapper(Tree, table, + properties={ + # set up a backref using a string + #'father':relation(Tree, foreignkey=table.c.id,primaryjoin=table.c.father_id==table.c.id, backref='childs')}, + + # or set up using the backref() function, which allows arguments to be passed + 'childs':relation(Tree, foreignkey=table.c.father_id, primaryjoin=table.c.father_id==table.c.id, backref=backref('father', uselist=False, foreignkey=table.c.id))}, + ) + +table.create() +root = Tree('root') +child1 = Tree('child1', root) +child2 = Tree('child2', root) +child3 = Tree('child3', child1) + +objectstore.commit() + +print root.childs +print child1.childs +print child2.childs +print child2.father +print child3.father </ins></span></pre></div> <a id="sqlalchemytrunklibsqlalchemymapping__init__py"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/mapping/__init__.py (1106 => 1107)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/mapping/__init__.py 2006-03-06 23:15:47 UTC (rev 1106) +++ sqlalchemy/trunk/lib/sqlalchemy/mapping/__init__.py 2006-03-07 03:14:08 UTC (rev 1107) </span><span class="lines">@@ -19,7 +19,7 @@ </span><span class="cx"> from properties import * </span><span class="cx"> import mapper as mapperlib </span><span class="cx"> </span><del>-__all__ = ['relation', 'eagerload', 'lazyload', 'noload', 'deferred', 'defer', 'undefer', </del><ins>+__all__ = ['relation', 'backref', 'eagerload', 'lazyload', 'noload', 'deferred', 'defer', 'undefer', </ins><span class="cx"> 'mapper', 'clear_mappers', 'objectstore', 'sql', 'extension', 'class_mapper', 'object_mapper', 'MapperExtension', </span><span class="cx"> 'assign_mapper', 'cascade_mappers' </span><span class="cx"> ] </span><span class="lines">@@ -39,7 +39,12 @@ </span><span class="cx"> else: </span><span class="cx"> return EagerLoader(mapper, secondary, primaryjoin, secondaryjoin, **kwargs) </span><span class="cx"> </span><ins>+def backref(name, **kwargs): + return BackRef(name, **kwargs) + </ins><span class="cx"> def deferred(*columns, **kwargs): </span><ins>+ """returns a DeferredColumnProperty, which indicates this object attributes should only be loaded + from its corresponding table column when first accessed.""" </ins><span class="cx"> return DeferredColumnProperty(*columns, **kwargs) </span><span class="cx"> </span><span class="cx"> def mapper(class_, table=None, *args, **params): </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemymappingpropertiespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/mapping/properties.py (1106 => 1107)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/mapping/properties.py 2006-03-06 23:15:47 UTC (rev 1106) +++ sqlalchemy/trunk/lib/sqlalchemy/mapping/properties.py 2006-03-07 03:14:08 UTC (rev 1107) </span><span class="lines">@@ -136,7 +136,10 @@ </span><span class="cx"> print "'use_alias' argument to relation() is deprecated. eager loads automatically alias-ize tables now." </span><span class="cx"> self.order_by = order_by </span><span class="cx"> self.attributeext=attributeext </span><del>- self.backref = backref </del><ins>+ if isinstance(backref, str): + self.backref = BackRef(backref) + else: + self.backref = backref </ins><span class="cx"> self.is_backref = is_backref </span><span class="cx"> </span><span class="cx"> def copy(self): </span><span class="lines">@@ -197,27 +200,13 @@ </span><span class="cx"> # if a backref name is defined, set up an extension to populate </span><span class="cx"> # attributes in the other direction </span><span class="cx"> if self.backref is not None: </span><del>- self.attributeext = attributes.GenericBackrefExtension(self.backref) </del><ins>+ self.attributeext = self.backref.get_extension() </ins><span class="cx"> </span><span class="cx"> # set our class attribute </span><span class="cx"> self._set_class_attribute(parent.class_, key) </span><span class="cx"> </span><span class="cx"> if self.backref is not None: </span><del>- # try to set a LazyLoader on our mapper referencing the parent mapper - if not self.mapper.props.has_key(self.backref): - 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)); - else: - # else set one of us as the "backreference" - if not self.mapper.props[self.backref].is_backref: - self.is_backref=True </del><ins>+ self.backref.compile(self) </ins><span class="cx"> elif not objectstore.global_attributes.is_class_managed(parent.class_, key): </span><span class="cx"> raise ArgumentError("Non-primary property created for attribute '%s' on class '%s', but that attribute is not managed! Insure that the primary mapper for this class defines this property" % (key, parent.class_.__name__)) </span><span class="cx"> </span><span class="lines">@@ -816,7 +805,33 @@ </span><span class="cx"> kwargs = util.constructor_args(oldprop) </span><span class="cx"> mapper.set_property(key, class_(**kwargs )) </span><span class="cx"> </span><del>- </del><ins>+class BackRef(object): + """stores the name of a backreference property as well as a relation (PropertyLoader), + used to construct more customized backrefs""" + def __init__(self, key, **kwargs): + self.key = key + self.kwargs = kwargs + def compile(self, prop): + # try to set a LazyLoader on our mapper referencing the parent mapper + if not prop.mapper.props.has_key(self.key): + if prop.secondaryjoin is not None: + # if setting up a backref to a many-to-many, reverse the order + # of the "primary" and "secondary" joins + pj = prop.secondaryjoin + sj = prop.primaryjoin + else: + pj = prop.primaryjoin + sj = None + relation = LazyLoader(prop.parent, prop.secondary, pj, sj, backref=prop.key, is_backref=True, **self.kwargs) + prop.mapper.add_property(self.key, relation); + else: + # else set one of us as the "backreference" + if not prop.mapper.props[self.key].is_backref: + prop.is_backref=True + + def get_extension(self): + return attributes.GenericBackrefExtension(self.key) + </ins><span class="cx"> class EagerLazyOption(GenericOption): </span><span class="cx"> """an option that switches a PropertyLoader to be an EagerLoader or LazyLoader""" </span><span class="cx"> def __init__(self, key, toeager = True, **kwargs): </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-03-06 23:15:58
|
<!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>[1106] sqlalchemy/trunk/lib/sqlalchemy/sql.py: checking in patch for column labels limit at 30 chars...what the heck</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1106</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-03-06 17:15:47 -0600 (Mon, 06 Mar 2006)</dd> </dl> <h3>Log Message</h3> <pre>checking in patch for column labels limit at 30 chars...what the heck</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunklibsqlalchemysqlpy">sqlalchemy/trunk/lib/sqlalchemy/sql.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 (1105 => 1106)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/sql.py 2006-03-06 19:09:30 UTC (rev 1105) +++ sqlalchemy/trunk/lib/sqlalchemy/sql.py 2006-03-06 23:15:47 UTC (rev 1106) </span><span class="lines">@@ -953,6 +953,7 @@ </span><span class="cx"> self.obj = obj </span><span class="cx"> obj.parens=True </span><span class="cx"> key = property(lambda s: s.name) </span><ins>+ </ins><span class="cx"> _label = property(lambda s: s.name) </span><span class="cx"> original = property(lambda s:s.obj.original) </span><span class="cx"> parent = property(lambda s:s.obj.parent) </span><span class="lines">@@ -971,11 +972,16 @@ </span><span class="cx"> self.key = self.name = self.text = text </span><span class="cx"> self.table = selectable </span><span class="cx"> self.type = type or sqltypes.NullTypeEngine() </span><ins>+ self.__label = None </ins><span class="cx"> def _get_label(self): </span><del>- if self.table is not None: - return self.table.name + "_" + self.text - else: - return self.text </del><ins>+ if self.__label is None: + if self.table is not None: + self.__label = self.table.name + "_" + self.text + else: + self.__label = self.text + if len(self.__label) >= 30: + self.__label = self.__label[0:24] + "_" + hex(random.randint(0, 65535))[2:] + return self.__label </ins><span class="cx"> _label = property(_get_label) </span><span class="cx"> def accept_visitor(self, visitor): </span><span class="cx"> visitor.visit_column(self) </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-03-06 19:09:45
|
<!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>[1105] sqlalchemy/trunk/lib/sqlalchemy/ansisql.py: patch on index create syntax to fix [ticket:90] so schema name gets included</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1105</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-03-06 13:09:30 -0600 (Mon, 06 Mar 2006)</dd> </dl> <h3>Log Message</h3> <pre>patch on index create syntax to fix [ticket:90] so schema name gets included</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunklibsqlalchemyansisqlpy">sqlalchemy/trunk/lib/sqlalchemy/ansisql.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 (1104 => 1105)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/ansisql.py 2006-03-06 19:06:06 UTC (rev 1104) +++ sqlalchemy/trunk/lib/sqlalchemy/ansisql.py 2006-03-06 19:09:30 UTC (rev 1105) </span><span class="lines">@@ -609,7 +609,7 @@ </span><span class="cx"> if index.unique: </span><span class="cx"> self.append('UNIQUE ') </span><span class="cx"> self.append('INDEX %s ON %s (%s)' \ </span><del>- % (index.name, index.table.name, </del><ins>+ % (index.name, index.table.fullname, </ins><span class="cx"> string.join([c.name for c in index.columns], ', '))) </span><span class="cx"> self.execute() </span><span class="cx"> </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-03-06 19:06:23
|
<!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>[1104] sqlalchemy/trunk/test: fixed bug in eager loading on a many-to-one [ticket:96], added the ticket tests as a unit test eagerload2.</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1104</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-03-06 13:06:06 -0600 (Mon, 06 Mar 2006)</dd> </dl> <h3>Log Message</h3> <pre>fixed bug in eager loading on a many-to-one [ticket:96], added the ticket tests as a unit test eagerload2. got eagerload1 to be a unit test also.</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunklibsqlalchemymappingpropertiespy">sqlalchemy/trunk/lib/sqlalchemy/mapping/properties.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemyutilpy">sqlalchemy/trunk/lib/sqlalchemy/util.py</a></li> <li><a href="#sqlalchemytrunktestalltestspy">sqlalchemy/trunk/test/alltests.py</a></li> <li><a href="#sqlalchemytrunktesteagertest1py">sqlalchemy/trunk/test/eagertest1.py</a></li> </ul> <h3>Added Paths</h3> <ul> <li><a href="#sqlalchemytrunktesteagertest2py">sqlalchemy/trunk/test/eagertest2.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 (1103 => 1104)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/mapping/properties.py 2006-03-06 17:14:50 UTC (rev 1103) +++ sqlalchemy/trunk/lib/sqlalchemy/mapping/properties.py 2006-03-06 19:06:06 UTC (rev 1104) </span><span class="lines">@@ -772,6 +772,11 @@ </span><span class="cx"> if not self.uselist: </span><span class="cx"> if isnew: </span><span class="cx"> h.setattr_clean(self._instance(row, imap)) </span><ins>+ else: + # call _instance on the row, even though the object has been created, + # so that we further descend into properties + self._instance(row, imap) + </ins><span class="cx"> return </span><span class="cx"> elif isnew: </span><span class="cx"> result_list = h </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemyutilpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/util.py (1103 => 1104)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/util.py 2006-03-06 17:14:50 UTC (rev 1103) +++ sqlalchemy/trunk/lib/sqlalchemy/util.py 2006-03-06 19:06:06 UTC (rev 1104) </span><span class="lines">@@ -229,6 +229,8 @@ </span><span class="cx"> return dict.__getitem__(self, key) </span><span class="cx"> except KeyError: </span><span class="cx"> return self.decorate[key] </span><ins>+ def __repr__(self): + return dict.__repr__(self) + repr(self.decorate) </ins><span class="cx"> class HashSet(object): </span><span class="cx"> """implements a Set.""" </span><span class="cx"> def __init__(self, iter=None, ordered=False): </span></span></pre></div> <a id="sqlalchemytrunktestalltestspy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/test/alltests.py (1103 => 1104)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/test/alltests.py 2006-03-06 17:14:50 UTC (rev 1103) +++ sqlalchemy/trunk/test/alltests.py 2006-03-06 19:06:06 UTC (rev 1104) </span><span class="lines">@@ -32,6 +32,8 @@ </span><span class="cx"> </span><span class="cx"> # ORM selecting </span><span class="cx"> 'mapper', </span><ins>+ 'eagertest1', + 'eagertest2', </ins><span class="cx"> </span><span class="cx"> # ORM persistence </span><span class="cx"> 'objectstore', </span></span></pre></div> <a id="sqlalchemytrunktesteagertest1py"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/test/eagertest1.py (1103 => 1104)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/test/eagertest1.py 2006-03-06 17:14:50 UTC (rev 1103) +++ sqlalchemy/trunk/test/eagertest1.py 2006-03-06 19:06:06 UTC (rev 1104) </span><span class="lines">@@ -1,60 +1,74 @@ </span><ins>+from testbase import PersistTest, AssertMixin +import testbase +import unittest, sys, os </ins><span class="cx"> from sqlalchemy import * </span><ins>+import datetime </ins><span class="cx"> </span><del>-class Part(object):pass -class Design(object):pass -class DesignType(object):pass -class InheritedPart(object):pass </del><ins>+class EagerTest(AssertMixin): + def setUpAll(self): + global designType, design, part, inheritedPart + + designType = Table('design_types', testbase.db, + Column('design_type_id', Integer, primary_key=True), + ) </ins><span class="cx"> </span><del>-engine = create_engine('sqlite://', echo=True) </del><ins>+ design =Table('design', testbase.db, + Column('design_id', Integer, primary_key=True), + Column('design_type_id', Integer, ForeignKey('design_types.design_type_id'))) </ins><span class="cx"> </span><del>-designType = Table('design_types', engine, - Column('design_type_id', Integer, primary_key=True), - ) </del><ins>+ part = Table('parts', testbase.db, + Column('part_id', Integer, primary_key=True), + Column('design_id', Integer, ForeignKey('design.design_id')), + Column('design_type_id', Integer, ForeignKey('design_types.design_type_id'))) </ins><span class="cx"> </span><del>-design =Table('design', engine, - Column('design_id', Integer, primary_key=True), - Column('design_type_id', Integer, ForeignKey('design_types.design_type_id'))) </del><ins>+ inheritedPart = Table('inherited_part', testbase.db, + Column('ip_id', Integer, primary_key=True), + Column('part_id', Integer, ForeignKey('parts.part_id')), + Column('design_id', Integer, ForeignKey('design.design_id')), + ) </ins><span class="cx"> </span><del>-part = Table('parts', engine, - Column('part_id', Integer, primary_key=True), - Column('design_id', Integer, ForeignKey('design.design_id')), - Column('design_type_id', Integer, ForeignKey('design_types.design_type_id'))) </del><ins>+ designType.create() + design.create() + part.create() + inheritedPart.create() + def tearDownAll(self): + inheritedPart.drop() + part.drop() + design.drop() + designType.drop() + + def testone(self): + class Part(object):pass + class Design(object):pass + class DesignType(object):pass + class InheritedPart(object):pass </ins><span class="cx"> </span><del>-inheritedPart = Table('inherited_part', engine, - Column('ip_id', Integer, primary_key=True), - Column('part_id', Integer, ForeignKey('parts.part_id')), - Column('design_id', Integer, ForeignKey('design.design_id')), - ) </del><ins>+ assign_mapper(Part, part) </ins><span class="cx"> </span><del>-designType.create() -design.create() -part.create() -inheritedPart.create() - -assign_mapper(Part, part) </del><ins>+ assign_mapper(InheritedPart, inheritedPart, properties=dict( + part=relation(Part, lazy=False) + )) </ins><span class="cx"> </span><del>-assign_mapper(InheritedPart, inheritedPart, properties=dict( - part=relation(Part, lazy=False) -)) </del><ins>+ assign_mapper(Design, design, properties=dict( + parts=relation(Part, private=True, backref="design"), + inheritedParts=relation(InheritedPart, private=True, backref="design"), + )) </ins><span class="cx"> </span><del>-assign_mapper(Design, design, properties=dict( - parts=relation(Part, private=True, backref="design"), - inheritedParts=relation(InheritedPart, private=True, backref="design"), -)) </del><ins>+ assign_mapper(DesignType, designType, properties=dict( + # designs=relation(Design, private=True, backref="type"), + )) </ins><span class="cx"> </span><del>-assign_mapper(DesignType, designType, properties=dict( -# designs=relation(Design, private=True, backref="type"), -)) </del><ins>+ Design.mapper.add_property("type", relation(DesignType, lazy=False, backref="designs")) + Part.mapper.add_property("design", relation(Design, lazy=False, backref="parts")) + #Part.mapper.add_property("designType", relation(DesignType)) </ins><span class="cx"> </span><del>-Design.mapper.add_property("type", relation(DesignType, lazy=False, backref="designs")) -Part.mapper.add_property("design", relation(Design, lazy=False, backref="parts")) -#Part.mapper.add_property("designType", relation(DesignType)) </del><ins>+ d = Design() + objectstore.commit() + objectstore.clear() + x = Design.get(1) + x.inheritedParts </ins><span class="cx"> </span><del>-d = Design() -objectstore.commit() -objectstore.clear() -print "lets go !\n\n\n" -x = Design.get(1) -x.inheritedParts </del><ins>+if __name__ == "__main__": + testbase.main() </ins><span class="cx"> </span><span class="cx"> </span></span></pre></div> <a id="sqlalchemytrunktesteagertest2py"></a> <div class="addfile"><h4>Added: sqlalchemy/trunk/test/eagertest2.py (1103 => 1104)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/test/eagertest2.py 2006-03-06 17:14:50 UTC (rev 1103) +++ sqlalchemy/trunk/test/eagertest2.py 2006-03-06 19:06:06 UTC (rev 1104) </span><span class="lines">@@ -0,0 +1,254 @@ </span><ins>+from testbase import PersistTest, AssertMixin +import testbase +import unittest, sys, os +from sqlalchemy import * +import datetime + +db = testbase.db + +class EagerTest(AssertMixin): + def setUpAll(self): + objectstore.clear() + clear_mappers() + testbase.db.tables.clear() + + global companies_table, addresses_table, invoice_table, phones_table, items_table + + companies_table = Table('companies', db, + Column('company_id', Integer, Sequence('company_id_seq', optional=True), primary_key = True), + Column('company_name', String(40)), + + ) + + addresses_table = Table('addresses', db, + Column('address_id', Integer, Sequence('address_id_seq', optional=True), primary_key = True), + Column('company_id', Integer, ForeignKey("companies.company_id")), + Column('address', String(40)), + ) + + phones_table = Table('phone_numbers', db, + Column('phone_id', Integer, Sequence('phone_id_seq', optional=True), primary_key = True), + Column('address_id', Integer, ForeignKey('addresses.address_id')), + Column('type', String(20)), + Column('number', String(10)), + ) + + invoice_table = Table('invoices', db, + Column('invoice_id', Integer, Sequence('invoice_id_seq', optional=True), primary_key = True), + Column('company_id', Integer, ForeignKey("companies.company_id")), + Column('date', DateTime), + ) + + items_table = Table('items', db, + Column('item_id', Integer, Sequence('item_id_seq', optional=True), primary_key = True), + Column('invoice_id', Integer, ForeignKey('invoices.invoice_id')), + Column('code', String(20)), + Column('qty', Integer), + ) + + companies_table.create() + addresses_table.create() + phones_table.create() + invoice_table.create() + items_table.create() + + def tearDownAll(self): + items_table.drop() + invoice_table.drop() + phones_table.drop() + addresses_table.drop() + companies_table.drop() + + def tearDown(self): + objectstore.clear() + clear_mappers() + items_table.delete().execute() + invoice_table.delete().execute() + phones_table.delete().execute() + addresses_table.delete().execute() + companies_table.delete().execute() + + def testone(self): + """tests eager load of a many-to-one attached to a one-to-many. this testcase illustrated + the bug, which is that when the single Company is loaded, no further processing of the rows + occurred in order to load the Company's second Address object.""" + class Company(object): + def __init__(self): + self.company_id = None + def __repr__(self): + return "Company:" + repr(getattr(self, 'company_id', None)) + " " + repr(getattr(self, 'company_name', None)) + " " + str([repr(addr) for addr in self.addresses]) + + class Address(object): + def __repr__(self): + return "Address: " + repr(getattr(self, 'address_id', None)) + " " + repr(getattr(self, 'company_id', None)) + " " + repr(self.address) + + class Invoice(object): + def __init__(self): + self.invoice_id = None + def __repr__(self): + return "Invoice:" + repr(getattr(self, 'invoice_id', None)) + " " + repr(getattr(self, 'date', None)) + " " + repr(self.company) + + Address.mapper = mapper(Address, addresses_table, properties={ + }) + Company.mapper = mapper(Company, companies_table, properties={ + 'addresses' : relation(Address.mapper, lazy=False), + }) + Invoice.mapper = mapper(Invoice, invoice_table, properties={ + 'company': relation(Company.mapper, lazy=False, ) + }) + + c1 = Company() + c1.company_name = 'company 1' + a1 = Address() + a1.address = 'a1 address' + c1.addresses.append(a1) + a2 = Address() + a2.address = 'a2 address' + c1.addresses.append(a2) + i1 = Invoice() + i1.date = datetime.datetime.now() + i1.company = c1 + + + objectstore.commit() + + company_id = c1.company_id + invoice_id = i1.invoice_id + + objectstore.clear() + + c = Company.mapper.get(company_id) + + objectstore.clear() + + i = Invoice.mapper.get(invoice_id) + + self.echo(repr(c)) + self.echo(repr(i.company)) + self.assert_(repr(c) == repr(i.company)) + + def testtwo(self): + """this is the original testcase that includes various complicating factors""" + class Company(object): + def __init__(self): + self.company_id = None + def __repr__(self): + return "Company:" + repr(getattr(self, 'company_id', None)) + " " + repr(getattr(self, 'company_name', None)) + " " + str([repr(addr) for addr in self.addresses]) + + class Address(object): + def __repr__(self): + return "Address: " + repr(getattr(self, 'address_id', None)) + " " + repr(getattr(self, 'company_id', None)) + " " + repr(self.address) + str([repr(ph) for ph in self.phones]) + + class Phone(object): + def __repr__(self): + return "Phone: " + repr(getattr(self, 'phone_id', None)) + " " + repr(getattr(self, 'address_id', None)) + " " + repr(self.type) + " " + repr(self.number) + + class Invoice(object): + def __init__(self): + self.invoice_id = None + def __repr__(self): + return "Invoice:" + repr(getattr(self, 'invoice_id', None)) + " " + repr(getattr(self, 'date', None)) + " " + repr(self.company) + " " + str([repr(item) for item in self.items]) + + class Item(object): + def __repr__(self): + return "Item: " + repr(getattr(self, 'item_id', None)) + " " + repr(getattr(self, 'invoice_id', None)) + " " + repr(self.code) + " " + repr(self.qty) + + Phone.mapper = mapper(Phone, phones_table, is_primary=True) + + Address.mapper = mapper(Address, addresses_table, properties={ + 'phones': relation(Phone.mapper, lazy=False, backref='address') + }) + + Company.mapper = mapper(Company, companies_table, properties={ + 'addresses' : relation(Address.mapper, lazy=False, backref='company'), + }) + + Item.mapper = mapper(Item, items_table, is_primary=True) + + Invoice.mapper = mapper(Invoice, invoice_table, properties={ + 'items': relation(Item.mapper, lazy=False, backref='invoice'), + 'company': relation(Company.mapper, lazy=False, backref='invoices') + }) + + objectstore.clear() + c1 = Company() + c1.company_name = 'company 1' + + a1 = Address() + a1.address = 'a1 address' + + p1 = Phone() + p1.type = 'home' + p1.number = '1111' + + a1.phones.append(p1) + + p2 = Phone() + p2.type = 'work' + p2.number = '22222' + a1.phones.append(p2) + + c1.addresses.append(a1) + + a2 = Address() + a2.address = 'a2 address' + + p3 = Phone() + p3.type = 'home' + p3.number = '3333' + a2.phones.append(p3) + + p4 = Phone() + p4.type = 'work' + p4.number = '44444' + a2.phones.append(p4) + + c1.addresses.append(a2) + + objectstore.commit() + + company_id = c1.company_id + + objectstore.clear() + + a = Company.mapper.get(company_id) + self.echo(repr(a)) + + # set up an invoice + i1 = Invoice() + i1.date = datetime.datetime.now() + i1.company = c1 + + item1 = Item() + item1.code = 'aaaa' + item1.qty = 1 + item1.invoice = i1 + + item2 = Item() + item2.code = 'bbbb' + item2.qty = 2 + item2.invoice = i1 + + item3 = Item() + item3.code = 'cccc' + item3.qty = 3 + item3.invoice = i1 + + objectstore.commit() + + invoice_id = i1.invoice_id + + objectstore.clear() + + c = Company.mapper.get(company_id) + self.echo(repr(c)) + + objectstore.clear() + + i = Invoice.mapper.get(invoice_id) + self.echo(repr(i)) + + self.assert_(repr(i.company) == repr(c)) + +if __name__ == "__main__": + testbase.main() </ins></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-03-06 17:15: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>[1103] sqlalchemy/trunk/lib/sqlalchemy/databases/sqlite.py: sqlite likes OFFSET with LIMIT else its buggy</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1103</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-03-06 11:14:50 -0600 (Mon, 06 Mar 2006)</dd> </dl> <h3>Log Message</h3> <pre>sqlite likes OFFSET with LIMIT else its buggy</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunklibsqlalchemydatabasessqlitepy">sqlalchemy/trunk/lib/sqlalchemy/databases/sqlite.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunklibsqlalchemydatabasessqlitepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/databases/sqlite.py (1102 => 1103)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/databases/sqlite.py 2006-03-06 03:10:46 UTC (rev 1102) +++ sqlalchemy/trunk/lib/sqlalchemy/databases/sqlite.py 2006-03-06 17:14:50 UTC (rev 1103) </span><span class="lines">@@ -222,6 +222,8 @@ </span><span class="cx"> if select.limit is None: </span><span class="cx"> text += " \n LIMIT -1" </span><span class="cx"> text += " OFFSET " + str(select.offset) </span><ins>+ else: + text += " OFFSET 0" </ins><span class="cx"> return text </span><span class="cx"> def binary_operator_string(self, binary): </span><span class="cx"> if isinstance(binary.type, sqltypes.String) and binary.operator == '+': </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>[1102] sqlalchemy/trunk/lib/sqlalchemy: a mapper with inheritance will place itself as "dependent" on the inherited mapper; even though this is not usually needed, it allows certain exotic combinations of mapper setups to work (i.e.</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1102</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-03-05 21:10:46 -0600 (Sun, 05 Mar 2006)</dd> </dl> <h3>Log Message</h3> <pre>a mapper with inheritance will place itself as "dependent" on the inherited mapper; even though this is not usually needed, it allows certain exotic combinations of mapper setups to work (i.e. the one in the polymorph example)</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunkexamplespolymorphpolymorphpy">sqlalchemy/trunk/examples/polymorph/polymorph.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="#sqlalchemytrunklibsqlalchemysqlpy">sqlalchemy/trunk/lib/sqlalchemy/sql.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunkexamplespolymorphpolymorphpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/examples/polymorph/polymorph.py (1101 => 1102)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/examples/polymorph/polymorph.py 2006-03-06 02:27:13 UTC (rev 1101) +++ sqlalchemy/trunk/examples/polymorph/polymorph.py 2006-03-06 03:10:46 UTC (rev 1102) </span><span class="lines">@@ -6,7 +6,8 @@ </span><span class="cx"> # extend from a common base class, although this same approach can be used </span><span class="cx"> # with </span><span class="cx"> </span><del>-db = create_engine('sqlite://', echo=True, echo_uow=False) </del><ins>+#db = create_engine('sqlite://', echo=True, echo_uow=False) +db = create_engine('postgres://user=scott&password=tiger&host=127.0.0.1&database=test', echo=True, echo_uow=False) </ins><span class="cx"> </span><span class="cx"> # a table to store companies </span><span class="cx"> companies = Table('companies', db, </span><span class="lines">@@ -52,9 +53,10 @@ </span><span class="cx"> assign_mapper(Manager, managers, inherits=Person.mapper) </span><span class="cx"> </span><span class="cx"> # next, we define a query that is going to load Managers and Engineers in one shot. </span><del>-# this query is tricky since the managers and engineers tables contain the same "description" column, -# so we set up a full blown select() statement that uses aliases for the description -# column. The select() statement is also given an alias 'pjoin', since the mapper requires </del><ins>+# we will use a UNION ALL with an extra hardcoded column to indicate the type of object. +# this can also be done via several LEFT OUTER JOINS but a UNION is more appropriate +# since they are distinct result sets. +# The select() statement is also given an alias 'pjoin', since the mapper requires </ins><span class="cx"> # that all Selectables have a name. </span><span class="cx"> # </span><span class="cx"> # TECHNIQUE - when you want to load a certain set of objects from a in one query, all the </span><span class="lines">@@ -65,7 +67,7 @@ </span><span class="cx"> # </span><span class="cx"> person_join = select( </span><span class="cx"> [people, managers.c.description,column("'manager'").label('type')], </span><del>- people.c.person_id==managers.c.person_id).union( </del><ins>+ people.c.person_id==managers.c.person_id).union_all( </ins><span class="cx"> select( </span><span class="cx"> [people, engineers.c.description, column("'engineer'").label('type')], </span><span class="cx"> people.c.person_id==engineers.c.person_id)).alias('pjoin') </span><span class="lines">@@ -89,20 +91,24 @@ </span><span class="cx"> ext = PersonLoader() </span><span class="cx"> </span><span class="cx"> # set up the polymorphic mapper, which maps the person_join we set up to </span><del>-# the Person class, using an instance of PersonLoader. Note that even though -# this mapper is against Person, its not going to screw up the normal operation -# of the Person object since its not the "primary" mapper. In reality, we could even -# make this mapper against some other class we dont care about since the creation of -# objects is hardcoded. </del><ins>+# the Person class, using an instance of PersonLoader. </ins><span class="cx"> people_mapper = mapper(Person, person_join, extension=ext) </span><span class="cx"> </span><ins>+# create a mapper for Company. the 'employees' relationship points to +# our new people_mapper. +# +# the dependency relationships which take effect on commit (i.e. the order of +# inserts/deletes) will be established against the Person class's primary +# mapper, and when the Engineer and +# Manager objects are found in the 'employees' list, the primary mappers +# for those subclasses will register +# themselves as dependent on the Person mapper's save operations. +# (translation: it'll work) +# TODO: get the eager loading to work (the compound select alias doesnt like being aliased itself) </ins><span class="cx"> assign_mapper(Company, companies, properties={ </span><del>- 'employees': relation(people_mapper), - 'engineers': relation(Engineer, private=True), - 'managers':relation(Manager, private=True) </del><ins>+ 'employees': relation(people_mapper, private=True) </ins><span class="cx"> }) </span><span class="cx"> </span><del>- </del><span class="cx"> c = Company(name='company1') </span><span class="cx"> c.employees.append(Manager(name='pointy haired boss', description='manager1')) </span><span class="cx"> c.employees.append(Engineer(name='dilbert', description='engineer1')) </span><span class="lines">@@ -128,4 +134,10 @@ </span><span class="cx"> print e, e._instance_key </span><span class="cx"> </span><span class="cx"> objectstore.delete(c) </span><del>-objectstore.commit() </del><span class="cx">\ No newline at end of file </span><ins>+objectstore.commit() + + +managers.drop() +engineers.drop() +people.drop() +companies.drop() </ins></span></pre></div> <a id="sqlalchemytrunklibsqlalchemymappingmapperpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/mapping/mapper.py (1101 => 1102)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/mapping/mapper.py 2006-03-06 02:27:13 UTC (rev 1101) +++ sqlalchemy/trunk/lib/sqlalchemy/mapping/mapper.py 2006-03-06 03:10:46 UTC (rev 1102) </span><span class="lines">@@ -67,9 +67,11 @@ </span><span class="cx"> self.table = sql.join(inherits.table, table, inherit_condition) </span><span class="cx"> self._synchronizer = sync.ClauseSynchronizer(self, self, sync.ONETOMANY) </span><span class="cx"> self._synchronizer.compile(self.table.onclause, inherits.tables, TableFinder(table)) </span><ins>+ self.inherits = inherits </ins><span class="cx"> else: </span><span class="cx"> self.primarytable = self.table </span><span class="cx"> self._synchronizer = None </span><ins>+ self.inherits = None </ins><span class="cx"> </span><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><span class="lines">@@ -670,13 +672,15 @@ </span><span class="cx"> except KeyError: </span><span class="cx"> return False </span><span class="cx"> </span><del>- def register_dependencies(self, *args, **kwargs): </del><ins>+ def register_dependencies(self, uowcommit, *args, **kwargs): </ins><span class="cx"> """called by an instance of objectstore.UOWTransaction to register </span><span class="cx"> which mappers are dependent on which, as well as DependencyProcessor </span><span class="cx"> objects which will process lists of objects in between saves and deletes.""" </span><span class="cx"> for prop in self.props.values(): </span><del>- prop.register_dependencies(*args, **kwargs) - </del><ins>+ prop.register_dependencies(uowcommit, *args, **kwargs) + if self.inherits is not None: + uowcommit.register_dependency(self.inherits, self) + </ins><span class="cx"> def register_deleted(self, obj, uow): </span><span class="cx"> for prop in self.props.values(): </span><span class="cx"> prop.register_deleted(obj, uow) </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemymappingobjectstorepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/mapping/objectstore.py (1101 => 1102)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/mapping/objectstore.py 2006-03-06 02:27:13 UTC (rev 1101) +++ sqlalchemy/trunk/lib/sqlalchemy/mapping/objectstore.py 2006-03-06 03:10:46 UTC (rev 1102) </span><span class="lines">@@ -534,7 +534,6 @@ </span><span class="cx"> def register_dependency(self, mapper, dependency): </span><span class="cx"> """called by mapper.PropertyLoader to register the objects handled by </span><span class="cx"> one mapper being dependent on the objects handled by another.""" </span><del>- </del><span class="cx"> # correct for primary mapper (the mapper offcially associated with the class) </span><span class="cx"> self.dependencies[(mapper._primary_mapper(), dependency._primary_mapper())] = True </span><span class="cx"> self.__modified = True </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemysqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/sql.py (1101 => 1102)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/sql.py 2006-03-06 02:27:13 UTC (rev 1101) +++ sqlalchemy/trunk/lib/sqlalchemy/sql.py 2006-03-06 03:10:46 UTC (rev 1102) </span><span class="lines">@@ -1211,7 +1211,6 @@ </span><span class="cx"> self.visit_select(cs) </span><span class="cx"> for s in cs.selects: </span><span class="cx"> s.parens = False </span><del>- print "BUT", id(cs), cs.parens </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-03-06 02:27:24
|
<!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>[1101] sqlalchemy/trunk/examples: added new 'polymorphic' example.</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1101</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-03-05 20:27:13 -0600 (Sun, 05 Mar 2006)</dd> </dl> <h3>Log Message</h3> <pre>added new 'polymorphic' example. still trying to understand it :) . fixes to relation to enable it to locate "direction" more consistently with inheritance relationships more tweaks to parenthesizing subqueries, unions, etc.</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunklibsqlalchemyansisqlpy">sqlalchemy/trunk/lib/sqlalchemy/ansisql.py</a></li> <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="#sqlalchemytrunklibsqlalchemysqlpy">sqlalchemy/trunk/lib/sqlalchemy/sql.py</a></li> </ul> <h3>Added Paths</h3> <ul> <li>sqlalchemy/trunk/examples/polymorph/</li> <li><a href="#sqlalchemytrunkexamplespolymorphpolymorphpy">sqlalchemy/trunk/examples/polymorph/polymorph.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunkexamplespolymorphpolymorphpy"></a> <div class="addfile"><h4>Added: sqlalchemy/trunk/examples/polymorph/polymorph.py (1100 => 1101)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/examples/polymorph/polymorph.py 2006-03-06 01:17:12 UTC (rev 1100) +++ sqlalchemy/trunk/examples/polymorph/polymorph.py 2006-03-06 02:27:13 UTC (rev 1101) </span><span class="lines">@@ -0,0 +1,131 @@ </span><ins>+from sqlalchemy import * +import sys + +# this example illustrates how to create a relationship to a list of objects, +# where each object in the list has a different type. The typed objects will +# extend from a common base class, although this same approach can be used +# with + +db = create_engine('sqlite://', echo=True, echo_uow=False) + +# a table to store companies +companies = Table('companies', db, + Column('company_id', Integer, primary_key=True), + Column('name', String(50))).create() + +# we will define an inheritance relationship between the table "people" and "engineers", +# and a second inheritance relationship between the table "people" and "managers" +people = Table('people', db, + Column('person_id', Integer, primary_key=True), + Column('company_id', Integer, ForeignKey('companies.company_id')), + Column('name', String(50))).create() + +engineers = Table('engineers', db, + Column('person_id', Integer, ForeignKey('people.person_id'), primary_key=True), + Column('description', String(50))).create() + +managers = Table('managers', db, + Column('person_id', Integer, ForeignKey('people.person_id'), primary_key=True), + Column('description', String(50))).create() + + +# create our classes. The Engineer and Manager classes extend from Person. +class Person(object): + def __repr__(self): + return "Ordinary person %s" % self.name +class Engineer(Person): + def __repr__(self): + return "Engineer %s, description %s" % (self.name, self.description) +class Manager(Person): + def __repr__(self): + return "Manager %s, description %s" % (self.name, self.description) +class Company(object): + def __repr__(self): + return "Company %s" % self.name + +# next we assign Person mappers. Since these are the first mappers we are +# creating for these classes, they automatically become the "primary mappers", which +# define the dependency relationships between the classes, so we do a straight +# inheritance setup, i.e. no modifications to how objects are loaded or anything like that. +assign_mapper(Person, people) +assign_mapper(Engineer, engineers, inherits=Person.mapper) +assign_mapper(Manager, managers, inherits=Person.mapper) + +# next, we define a query that is going to load Managers and Engineers in one shot. +# this query is tricky since the managers and engineers tables contain the same "description" column, +# so we set up a full blown select() statement that uses aliases for the description +# column. The select() statement is also given an alias 'pjoin', since the mapper requires +# that all Selectables have a name. +# +# TECHNIQUE - when you want to load a certain set of objects from a in one query, all the +# columns in the Selectable must have unique names. Dont worry about mappers at this point, +# just worry about making a query where if you were to view the results, you could tell everything +# you need to know from each row how to construct an object instance from it. this is the +# essence of "resultset-based-mapping", which is the core ideology of SQLAlchemy. +# +person_join = select( + [people, managers.c.description,column("'manager'").label('type')], + people.c.person_id==managers.c.person_id).union( + select( + [people, engineers.c.description, column("'engineer'").label('type')], + people.c.person_id==engineers.c.person_id)).alias('pjoin') + + +# lets print out what this Selectable looks like. The mapper is going to take the selectable and +# Select off of it, with the flag "use_labels" which indicates to prefix column names with the table +# name. So here is what our mapper will see: +print "Person selectable:", str(person_join.select(use_labels=True)), "\n" + + +# MapperExtension object. +class PersonLoader(MapperExtension): + def create_instance(self, mapper, row, imap, class_): + if row['pjoin_type'] =='engineer': + return Engineer() + elif row['pjoin_type'] =='manager': + return Manager() + else: + return Person() +ext = PersonLoader() + +# set up the polymorphic mapper, which maps the person_join we set up to +# the Person class, using an instance of PersonLoader. Note that even though +# this mapper is against Person, its not going to screw up the normal operation +# of the Person object since its not the "primary" mapper. In reality, we could even +# make this mapper against some other class we dont care about since the creation of +# objects is hardcoded. +people_mapper = mapper(Person, person_join, extension=ext) + +assign_mapper(Company, companies, properties={ + 'employees': relation(people_mapper), + 'engineers': relation(Engineer, private=True), + 'managers':relation(Manager, private=True) +}) + + +c = Company(name='company1') +c.employees.append(Manager(name='pointy haired boss', description='manager1')) +c.employees.append(Engineer(name='dilbert', description='engineer1')) +c.employees.append(Engineer(name='wally', description='engineer2')) +c.employees.append(Manager(name='jsmith', description='manager2')) +objectstore.commit() + +objectstore.clear() + +c = Company.get(1) +for e in c.employees: + print e, e._instance_key + +print "\n" + +dilbert = c.employees[1] +dilbert.description = 'hes dibert!' +objectstore.commit() + +objectstore.clear() +c = Company.get(1) +for e in c.employees: + print e, e._instance_key + +objectstore.delete(c) +objectstore.commit() </ins><span class="cx">\ No newline at end of file </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemyansisqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/ansisql.py (1100 => 1101)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/ansisql.py 2006-03-06 01:17:12 UTC (rev 1100) +++ sqlalchemy/trunk/lib/sqlalchemy/ansisql.py 2006-03-06 02:27:13 UTC (rev 1101) </span><span class="lines">@@ -240,7 +240,10 @@ </span><span class="cx"> text = string.join([self.get_str(c) for c in cs.selects], " " + cs.keyword + " ") </span><span class="cx"> for tup in cs.clauses: </span><span class="cx"> text += " " + tup[0] + " " + self.get_str(tup[1]) </span><del>- self.strings[cs] = text </del><ins>+ if cs.parens: + self.strings[cs] = "(" + text + ")" + else: + self.strings[cs] = text </ins><span class="cx"> self.froms[cs] = "(" + text + ")" </span><span class="cx"> </span><span class="cx"> def visit_binary(self, binary): </span><span class="lines">@@ -368,7 +371,7 @@ </span><span class="cx"> </span><span class="cx"> text += self.visit_select_postclauses(select) </span><span class="cx"> </span><del>- if getattr(select, 'useparens', False): </del><ins>+ if getattr(select, 'parens', False): </ins><span class="cx"> self.strings[select] = "(" + text + ")" </span><span class="cx"> else: </span><span class="cx"> self.strings[select] = text </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemymappingmapperpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/mapping/mapper.py (1100 => 1101)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/mapping/mapper.py 2006-03-06 01:17:12 UTC (rev 1100) +++ sqlalchemy/trunk/lib/sqlalchemy/mapping/mapper.py 2006-03-06 02:27:13 UTC (rev 1101) </span><span class="lines">@@ -952,7 +952,6 @@ </span><span class="cx"> </span><span class="cx"> def class_mapper(class_): </span><span class="cx"> """given a class, returns the primary Mapper associated with the class.""" </span><del>- return mapper_registry[class_] </del><span class="cx"> try: </span><span class="cx"> return mapper_registry[class_] </span><span class="cx"> except KeyError: </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemymappingpropertiespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/mapping/properties.py (1100 => 1101)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/mapping/properties.py 2006-03-06 01:17:12 UTC (rev 1100) +++ sqlalchemy/trunk/lib/sqlalchemy/mapping/properties.py 2006-03-06 02:27:13 UTC (rev 1101) </span><span class="lines">@@ -229,7 +229,8 @@ </span><span class="cx"> </span><span class="cx"> def _get_direction(self): </span><span class="cx"> """determines our 'direction', i.e. do we represent one to many, many to many, etc.""" </span><del>-# print self.key, repr(self.parent.table.name), repr(self.parent.primarytable.name), repr(self.foreignkey.table.name) </del><ins>+ #print self.key, repr(self.parent.table.name), repr(self.parent.primarytable.name), repr(self.foreignkey.table.name), repr(self.target), repr(self.foreigntable.name) + </ins><span class="cx"> if self.parent.table is self.target: </span><span class="cx"> if self.foreignkey.primary_key: </span><span class="cx"> return PropertyLoader.MANYTOONE </span><span class="lines">@@ -237,9 +238,9 @@ </span><span class="cx"> return PropertyLoader.ONETOMANY </span><span class="cx"> elif self.secondaryjoin is not None: </span><span class="cx"> return PropertyLoader.MANYTOMANY </span><del>- elif self.foreigntable == self.target: </del><ins>+ elif self.foreigntable is self.target or self.foreigntable in self.mapper.tables: </ins><span class="cx"> return PropertyLoader.ONETOMANY </span><del>- elif self.foreigntable == self.parent.table: </del><ins>+ elif self.foreigntable is self.parent.table or self.foreigntable in self.parent.tables: </ins><span class="cx"> return PropertyLoader.MANYTOONE </span><span class="cx"> else: </span><span class="cx"> raise ArgumentError("Cant determine relation direction") </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemysqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/sql.py (1100 => 1101)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/sql.py 2006-03-06 01:17:12 UTC (rev 1100) +++ sqlalchemy/trunk/lib/sqlalchemy/sql.py 2006-03-06 02:27:13 UTC (rev 1101) </span><span class="lines">@@ -454,7 +454,7 @@ </span><span class="cx"> # assume *other is a list of selects. </span><span class="cx"> # so put them in a UNION. if theres only one, you just get one SELECT </span><span class="cx"> # statement out of it. </span><del>- return self._compare('IN', union(*other)) </del><ins>+ return self._compare('IN', union(parens=True, *other)) </ins><span class="cx"> def startswith(self, other): </span><span class="cx"> return self._compare('LIKE', str(other) + "%") </span><span class="cx"> def endswith(self, other): </span><span class="lines">@@ -1123,6 +1123,7 @@ </span><span class="cx"> self.keyword = keyword </span><span class="cx"> self.selects = selects </span><span class="cx"> self.use_labels = kwargs.pop('use_labels', False) </span><ins>+ self.parens = kwargs.pop('parens', False) </ins><span class="cx"> self.oid_column = selects[0].oid_column </span><span class="cx"> for s in self.selects: </span><span class="cx"> s.group_by(None) </span><span class="lines">@@ -1209,7 +1210,8 @@ </span><span class="cx"> def visit_compound_select(self, cs): </span><span class="cx"> self.visit_select(cs) </span><span class="cx"> for s in cs.selects: </span><del>- s.useparens = False </del><ins>+ s.parens = False + print "BUT", id(cs), cs.parens </ins><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 class="lines">@@ -1217,7 +1219,7 @@ </span><span class="cx"> return </span><span class="cx"> select.is_where = self.is_where </span><span class="cx"> select.issubquery = True </span><del>- select.useparens = True </del><ins>+ select.parens = True </ins><span class="cx"> if getattr(select, '_correlated', None) is None: </span><span class="cx"> select._correlated = self.select._froms </span><span class="cx"> </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-03-06 01:17:21
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head><style type="text/css"><!-- #msg dl { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; } #msg dt { float: left; width: 6em; font-weight: bold; } #msg dt:after { content:':';} #msg dl, #msg dt, #msg ul, #msg li { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; } #msg dl a { font-weight: bold} #msg dl a:link { color:#fc3; } #msg dl a:active { color:#ff0; } #msg dl a:visited { color:#cc6; } h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; } #msg pre { overflow: auto; background: #ffc; border: 1px #fc0 solid; padding: 6px; } #msg ul, pre { overflow: auto; } #patch { width: 100%; } #patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;} #patch .propset h4, #patch .binary h4 {margin:0;} #patch pre {padding:0;line-height:1.2em;margin:0;} #patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;} #patch .propset .diff, #patch .binary .diff {padding:10px 0;} #patch span {display:block;padding:0 10px;} #patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;} #patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;} #patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;} #patch .lines, .info {color:#888;background:#fff;} --></style> <title>[1100] sqlalchemy/trunk/lib/sqlalchemy: more tweak to compoundselect parenthesizing/subquery flag</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1100</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-03-05 19:17:12 -0600 (Sun, 05 Mar 2006)</dd> </dl> <h3>Log Message</h3> <pre>more tweak to compoundselect parenthesizing/subquery flag</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunklibsqlalchemyansisqlpy">sqlalchemy/trunk/lib/sqlalchemy/ansisql.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemysqlpy">sqlalchemy/trunk/lib/sqlalchemy/sql.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunklibsqlalchemyansisqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/ansisql.py (1099 => 1100)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/ansisql.py 2006-03-06 01:09:03 UTC (rev 1099) +++ sqlalchemy/trunk/lib/sqlalchemy/ansisql.py 2006-03-06 01:17:12 UTC (rev 1100) </span><span class="lines">@@ -186,7 +186,7 @@ </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 is not None and column.table.name is None: </del><ins>+ if column.table is None or 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="lines">@@ -368,7 +368,7 @@ </span><span class="cx"> </span><span class="cx"> text += self.visit_select_postclauses(select) </span><span class="cx"> </span><del>- if getattr(select, 'issubquery', False): </del><ins>+ if getattr(select, 'useparens', False): </ins><span class="cx"> self.strings[select] = "(" + text + ")" </span><span class="cx"> else: </span><span class="cx"> self.strings[select] = text </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemysqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/sql.py (1099 => 1100)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/sql.py 2006-03-06 01:09:03 UTC (rev 1099) +++ sqlalchemy/trunk/lib/sqlalchemy/sql.py 2006-03-06 01:17:12 UTC (rev 1100) </span><span class="lines">@@ -1208,11 +1208,8 @@ </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>- # unselect the 'issubquery' flag on the selects within the compound, - # i.e. "SELECT foo UNION SELECT bar", since the enclosing compound select - # is the "subquery" </del><span class="cx"> for s in cs.selects: </span><del>- s.issubquery = False </del><ins>+ s.useparens = False </ins><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 class="lines">@@ -1220,6 +1217,7 @@ </span><span class="cx"> return </span><span class="cx"> select.is_where = self.is_where </span><span class="cx"> select.issubquery = True </span><ins>+ select.useparens = True </ins><span class="cx"> if getattr(select, '_correlated', None) is None: </span><span class="cx"> select._correlated = self.select._froms </span><span class="cx"> </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-03-06 01:09:14
|
<!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>[1099] sqlalchemy/trunk/lib/sqlalchemy/sql.py: selects within a compound clause dont get parenthesis added</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1099</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-03-05 19:09:03 -0600 (Sun, 05 Mar 2006)</dd> </dl> <h3>Log Message</h3> <pre>selects within a compound clause dont get parenthesis added fix to ColumnClause</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunklibsqlalchemysqlpy">sqlalchemy/trunk/lib/sqlalchemy/sql.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 (1098 => 1099)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/sql.py 2006-03-06 01:07:48 UTC (rev 1098) +++ sqlalchemy/trunk/lib/sqlalchemy/sql.py 2006-03-06 01:09:03 UTC (rev 1099) </span><span class="lines">@@ -635,6 +635,9 @@ </span><span class="cx"> Since compare() is meant to compare statement syntax, this method </span><span class="cx"> returns True if the two BindParamClauses have just the same type.""" </span><span class="cx"> return isinstance(other, BindParamClause) and other.type.__class__ == self.type.__class__ </span><ins>+ def _make_proxy(self, selectable, name = None): + return self +# return self.obj._make_proxy(selectable, name=self.name) </ins><span class="cx"> </span><span class="cx"> class TextClause(ClauseElement): </span><span class="cx"> """represents literal a SQL text fragment. public constructor is the </span><span class="lines">@@ -988,7 +991,7 @@ </span><span class="cx"> return BindParamClause(self.table.name + "_" + self.text, obj, shortname = self.text, type=self.type) </span><span class="cx"> def _make_proxy(self, selectable, name = None): </span><span class="cx"> c = ColumnClause(name or self.text, selectable) </span><del>- selectable.columns[c.key] = c </del><ins>+ selectable.columns[c.name] = c </ins><span class="cx"> return c </span><span class="cx"> def _compare_type(self, obj): </span><span class="cx"> return self.type </span><span class="lines">@@ -1205,6 +1208,11 @@ </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>+ # unselect the 'issubquery' flag on the selects within the compound, + # i.e. "SELECT foo UNION SELECT bar", since the enclosing compound select + # is the "subquery" + for s in cs.selects: + s.issubquery = False </ins><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-03-06 01:07:59
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head><style type="text/css"><!-- #msg dl { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; } #msg dt { float: left; width: 6em; font-weight: bold; } #msg dt:after { content:':';} #msg dl, #msg dt, #msg ul, #msg li { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; } #msg dl a { font-weight: bold} #msg dl a:link { color:#fc3; } #msg dl a:active { color:#ff0; } #msg dl a:visited { color:#cc6; } h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; } #msg pre { overflow: auto; background: #ffc; border: 1px #fc0 solid; padding: 6px; } #msg ul, pre { overflow: auto; } #patch { width: 100%; } #patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;} #patch .propset h4, #patch .binary h4 {margin:0;} #patch pre {padding:0;line-height:1.2em;margin:0;} #patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;} #patch .propset .diff, #patch .binary .diff {padding:10px 0;} #patch span {display:block;padding:0 10px;} #patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;} #patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;} #patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;} #patch .lines, .info {color:#888;background:#fff;} --></style> <title>[1098] sqlalchemy/trunk/lib/sqlalchemy/mapping/mapper.py: delete tables in an inheritance rel.</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1098</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-03-05 19:07:48 -0600 (Sun, 05 Mar 2006)</dd> </dl> <h3>Log Message</h3> <pre>delete tables in an inheritance rel. requires them in reverse</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 (1097 => 1098)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/mapping/mapper.py 2006-03-05 21:10:20 UTC (rev 1097) +++ sqlalchemy/trunk/lib/sqlalchemy/mapping/mapper.py 2006-03-06 01:07:48 UTC (rev 1098) </span><span class="lines">@@ -636,7 +636,9 @@ </span><span class="cx"> def delete_obj(self, objects, uow): </span><span class="cx"> """called by a UnitOfWork object to delete objects, which involves a </span><span class="cx"> DELETE statement for each table used by this mapper, for each object in the list.""" </span><del>- for table in self.tables: </del><ins>+ l = list(self.tables) + l.reverse() + for table in l: </ins><span class="cx"> if not self._has_pks(table): </span><span class="cx"> continue </span><span class="cx"> delete = [] </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>[1097] sqlalchemy/trunk/test: added unittest for orm-persisted insert without a postfetch, tweak to engine to only signal postfetch if the passivedefault columns received None/NULL for their parameter (since they dont exec otherwise)</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1097</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-03-05 15:10:20 -0600 (Sun, 05 Mar 2006)</dd> </dl> <h3>Log Message</h3> <pre>added unittest for orm-persisted insert without a postfetch, tweak to engine to only signal postfetch if the passivedefault columns received None/NULL for their parameter (since they dont exec otherwise)</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunklibsqlalchemyenginepy">sqlalchemy/trunk/lib/sqlalchemy/engine.py</a></li> <li><a href="#sqlalchemytrunktestobjectstorepy">sqlalchemy/trunk/test/objectstore.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 (1096 => 1097)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/engine.py 2006-03-05 21:01:21 UTC (rev 1096) +++ sqlalchemy/trunk/lib/sqlalchemy/engine.py 2006-03-05 21:10:20 UTC (rev 1097) </span><span class="lines">@@ -468,9 +468,9 @@ </span><span class="cx"> last_inserted_ids = [] </span><span class="cx"> need_lastrowid=False </span><span class="cx"> for c in compiled.statement.table.c: </span><del>- if isinstance(c.default, schema.PassiveDefault): - self.context.lastrow_has_defaults = True </del><span class="cx"> if not param.has_key(c.name) or param[c.name] is None: </span><ins>+ if isinstance(c.default, schema.PassiveDefault): + self.context.lastrow_has_defaults = True </ins><span class="cx"> newid = drunner.get_column_default(c) </span><span class="cx"> if newid is not None: </span><span class="cx"> param[c.name] = newid </span></span></pre></div> <a id="sqlalchemytrunktestobjectstorepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/test/objectstore.py (1096 => 1097)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/test/objectstore.py 2006-03-05 21:01:21 UTC (rev 1096) +++ sqlalchemy/trunk/test/objectstore.py 2006-03-05 21:10:20 UTC (rev 1097) </span><span class="lines">@@ -213,6 +213,9 @@ </span><span class="cx"> objectstore.commit() </span><span class="cx"> </span><span class="cx"> class DefaultTest(AssertMixin): </span><ins>+ """tests that when saving objects whose table contains DefaultGenerators, either python-side, preexec or database-side, + the newly saved instances receive all the default values either through a post-fetch or getting the pre-exec'ed + defaults back from the engine.""" </ins><span class="cx"> def setUpAll(self): </span><span class="cx"> #db.echo = 'debug' </span><span class="cx"> use_string_defaults = db.engine.__module__.endswith('postgres') or db.engine.__module__.endswith('oracle') or db.engine.__module__.endswith('sqlite') </span><span class="lines">@@ -236,8 +239,7 @@ </span><span class="cx"> self.table.drop() </span><span class="cx"> def setUp(self): </span><span class="cx"> self.table = Table('default_test', db) </span><del>- def testbasic(self): - </del><ins>+ def testinsert(self): </ins><span class="cx"> class Hoho(object):pass </span><span class="cx"> assign_mapper(Hoho, self.table) </span><span class="cx"> h1 = Hoho(hoho=self.althohoval) </span><span class="lines">@@ -264,6 +266,16 @@ </span><span class="cx"> self.assert_(h2.foober == h3.foober == h4.foober == 'im foober') </span><span class="cx"> self.assert_(h5.foober=='im the new foober') </span><span class="cx"> </span><ins>+ def testinsertnopostfetch(self): + # populates the PassiveDefaults explicitly so there is no "post-update" + class Hoho(object):pass + assign_mapper(Hoho, self.table) + h1 = Hoho(hoho="15", counter="15") + objectstore.commit() + self.assert_(h1.hoho=="15") + self.assert_(h1.counter=="15") + self.assert_(h1.foober=="im foober") + </ins><span class="cx"> def testupdate(self): </span><span class="cx"> class Hoho(object):pass </span><span class="cx"> assign_mapper(Hoho, self.table) </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-03-05 21:01:34
|
<!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>[1096] sqlalchemy/trunk/test: got mapper to receive the onupdates after updating an instance (also properly receives defaults on inserts)...</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1096</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-03-05 15:01:21 -0600 (Sun, 05 Mar 2006)</dd> </dl> <h3>Log Message</h3> <pre>got mapper to receive the onupdates after updating an instance (also properly receives defaults on inserts)...</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunklibsqlalchemyenginepy">sqlalchemy/trunk/lib/sqlalchemy/engine.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemymappingmapperpy">sqlalchemy/trunk/lib/sqlalchemy/mapping/mapper.py</a></li> <li><a href="#sqlalchemytrunktestobjectstorepy">sqlalchemy/trunk/test/objectstore.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 (1095 => 1096)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/engine.py 2006-03-05 20:31:44 UTC (rev 1095) +++ sqlalchemy/trunk/lib/sqlalchemy/engine.py 2006-03-05 21:01:21 UTC (rev 1096) </span><span class="lines">@@ -484,20 +484,33 @@ </span><span class="cx"> self.context.last_inserted_ids = None </span><span class="cx"> else: </span><span class="cx"> self.context.last_inserted_ids = last_inserted_ids </span><ins>+ self.context.last_inserted_params = param </ins><span class="cx"> elif getattr(compiled, 'isupdate', False): </span><span class="cx"> if isinstance(parameters, list): </span><span class="cx"> plist = parameters </span><span class="cx"> else: </span><span class="cx"> plist = [parameters] </span><span class="cx"> drunner = self.defaultrunner(proxy) </span><ins>+ self.context.lastrow_has_defaults = False </ins><span class="cx"> for param in plist: </span><span class="cx"> for c in compiled.statement.table.c: </span><span class="cx"> if c.onupdate is not None and (not param.has_key(c.name) or param[c.name] is None): </span><span class="cx"> value = drunner.get_column_onupdate(c) </span><span class="cx"> if value is not None: </span><span class="cx"> param[c.name] = value </span><del>- </del><ins>+ self.context.last_updated_params = param + + def last_inserted_params(self): + """returns a dictionary of the full parameter dictionary for the last compiled INSERT statement, + including any ColumnDefaults or Sequences that were pre-executed. this value is thread-local.""" + return self.context.last_inserted_params + def last_updated_params(self): + """returns a dictionary of the full parameter dictionary for the last compiled UPDATE statement, + including any ColumnDefaults that were pre-executed. this value is thread-local.""" + return self.context.last_updated_params </ins><span class="cx"> def lastrow_has_defaults(self): </span><ins>+ """returns True if the last row INSERTED via a compiled insert statement contained PassiveDefaults, + indicating that the database inserted data beyond that which we gave it. this value is thread-local.""" </ins><span class="cx"> return self.context.lastrow_has_defaults </span><span class="cx"> </span><span class="cx"> def pre_exec(self, proxy, compiled, parameters, **kwargs): </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemymappingmapperpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/mapping/mapper.py (1095 => 1096)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/mapping/mapper.py 2006-03-05 20:31:44 UTC (rev 1095) +++ sqlalchemy/trunk/lib/sqlalchemy/mapping/mapper.py 2006-03-05 21:01:21 UTC (rev 1096) </span><span class="lines">@@ -591,6 +591,7 @@ </span><span class="cx"> for rec in update: </span><span class="cx"> (obj, params) = rec </span><span class="cx"> c = statement.execute(params) </span><ins>+ self._postfetch(table, obj, table.engine.last_updated_params()) </ins><span class="cx"> self.extension.after_update(self, obj) </span><span class="cx"> rows += c.cursor.rowcount </span><span class="cx"> if table.engine.supports_sane_rowcount() and rows != len(update): </span><span class="lines">@@ -608,18 +609,30 @@ </span><span class="cx"> if self._getattrbycolumn(obj, col) is None: </span><span class="cx"> self._setattrbycolumn(obj, col, primary_key[i]) </span><span class="cx"> i+=1 </span><del>- if table.engine.lastrow_has_defaults(): - clause = sql.and_() - for p in self.pks_by_table[table]: - clause.clauses.append(p == self._getattrbycolumn(obj, p)) - row = table.select(clause).execute().fetchone() - for c in table.c: - if self._getattrbycolumn(obj, c) is None: - self._setattrbycolumn(obj, c, row[c]) </del><ins>+ self._postfetch(table, obj, table.engine.last_inserted_params()) </ins><span class="cx"> if self._synchronizer is not None: </span><span class="cx"> self._synchronizer.execute(obj, obj) </span><span class="cx"> self.extension.after_insert(self, obj) </span><del>- </del><ins>+ + def _postfetch(self, table, obj, params): + """after an INSERT or UPDATE, asks the engine if PassiveDefaults fired off on the database side + which need to be post-fetched, *or* if pre-exec defaults like ColumnDefaults were fired off + and should be populated into the instance. this is only for non-primary key columns.""" + if table.engine.lastrow_has_defaults(): + clause = sql.and_() + for p in self.pks_by_table[table]: + clause.clauses.append(p == self._getattrbycolumn(obj, p)) + row = table.select(clause).execute().fetchone() + for c in table.c: + if self._getattrbycolumn(obj, c) is None: + self._setattrbycolumn(obj, c, row[c]) + else: + for c in table.c: + if c.primary_key or not params.has_key(c.name): + continue + if self._getattrbycolumn(obj, c) != params[c.name]: + self._setattrbycolumn(obj, c, params[c.name]) + </ins><span class="cx"> def delete_obj(self, objects, uow): </span><span class="cx"> """called by a UnitOfWork object to delete objects, which involves a </span><span class="cx"> DELETE statement for each table used by this mapper, for each object in the list.""" </span></span></pre></div> <a id="sqlalchemytrunktestobjectstorepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/test/objectstore.py (1095 => 1096)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/test/objectstore.py 2006-03-05 20:31:44 UTC (rev 1095) +++ sqlalchemy/trunk/test/objectstore.py 2006-03-05 21:01:21 UTC (rev 1096) </span><span class="lines">@@ -229,11 +229,13 @@ </span><span class="cx"> Column('id', Integer, Sequence("dt_seq", optional=True), primary_key=True), </span><span class="cx"> Column('hoho', hohotype, PassiveDefault(str(self.hohoval))), </span><span class="cx"> Column('counter', Integer, PassiveDefault("7")), </span><del>- Column('foober', String(30), default="im foober") </del><ins>+ Column('foober', String(30), default="im foober", onupdate="im the update") </ins><span class="cx"> ) </span><span class="cx"> self.table.create() </span><span class="cx"> def tearDownAll(self): </span><span class="cx"> self.table.drop() </span><ins>+ def setUp(self): + self.table = Table('default_test', db) </ins><span class="cx"> def testbasic(self): </span><span class="cx"> </span><span class="cx"> class Hoho(object):pass </span><span class="lines">@@ -261,7 +263,17 @@ </span><span class="cx"> self.assert_(h1.counter == h4.counter==h5.counter==7) </span><span class="cx"> self.assert_(h2.foober == h3.foober == h4.foober == 'im foober') </span><span class="cx"> self.assert_(h5.foober=='im the new foober') </span><del>- </del><ins>+ + def testupdate(self): + class Hoho(object):pass + assign_mapper(Hoho, self.table) + h1 = Hoho() + objectstore.commit() + self.assert_(h1.foober == 'im foober') + h1.counter = 19 + objectstore.commit() + self.assert_(h1.foober == 'im the update') + </ins><span class="cx"> class SaveTest(AssertMixin): </span><span class="cx"> </span><span class="cx"> def setUpAll(self): </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-03-05 20:32:06
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head><style type="text/css"><!-- #msg dl { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; } #msg dt { float: left; width: 6em; font-weight: bold; } #msg dt:after { content:':';} #msg dl, #msg dt, #msg ul, #msg li { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; } #msg dl a { font-weight: bold} #msg dl a:link { color:#fc3; } #msg dl a:active { color:#ff0; } #msg dl a:visited { color:#cc6; } h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; } #msg pre { overflow: auto; background: #ffc; border: 1px #fc0 solid; padding: 6px; } #msg ul, pre { overflow: auto; } #patch { width: 100%; } #patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;} #patch .propset h4, #patch .binary h4 {margin:0;} #patch pre {padding:0;line-height:1.2em;margin:0;} #patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;} #patch .propset .diff, #patch .binary .diff {padding:10px 0;} #patch span {display:block;padding:0 10px;} #patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;} #patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;} #patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;} #patch .lines, .info {color:#888;background:#fff;} --></style> <title>[1095] sqlalchemy/trunk/test: got column onupdate working</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1095</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-03-05 14:31:44 -0600 (Sun, 05 Mar 2006)</dd> </dl> <h3>Log Message</h3> <pre>got column onupdate working improvement to Function so that they can more easily be called standalone without having to throw them into a select().</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunkdocbuildcontentsqlconstructionmyt">sqlalchemy/trunk/doc/build/content/sqlconstruction.myt</a></li> <li><a href="#sqlalchemytrunklibsqlalchemyansisqlpy">sqlalchemy/trunk/lib/sqlalchemy/ansisql.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemydatabasesoraclepy">sqlalchemy/trunk/lib/sqlalchemy/databases/oracle.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="#sqlalchemytrunklibsqlalchemyschemapy">sqlalchemy/trunk/lib/sqlalchemy/schema.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemysqlpy">sqlalchemy/trunk/lib/sqlalchemy/sql.py</a></li> <li><a href="#sqlalchemytrunktestdefaultspy">sqlalchemy/trunk/test/defaults.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunkdocbuildcontentsqlconstructionmyt"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/doc/build/content/sqlconstruction.myt (1094 => 1095)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/doc/build/content/sqlconstruction.myt 2006-03-04 20:23:37 UTC (rev 1094) +++ sqlalchemy/trunk/doc/build/content/sqlconstruction.myt 2006-03-05 20:31:44 UTC (rev 1095) </span><span class="lines">@@ -341,7 +341,18 @@ </span><span class="cx"> </&> </span><span class="cx"> </span><span class="cx"> </&> </span><ins>+ <p>Functions also are callable as standalone values:</p> + <&|formatting.myt:code &> + # call the "now()" function + time = func.now(engine=myengine).scalar() + + # call myfunc(1,2,3) + myvalue = func.myfunc(1, 2, 3, engine=db).execute() + + # or call them off the engine + db.func.now().scalar() </ins><span class="cx"> </&> </span><ins>+ </&> </ins><span class="cx"> <&|doclib.myt:item, name="literals", description="Literals" &> </span><span class="cx"> <p>You can drop in a literal value anywhere there isnt a column to attach to via the <span class="codeline">literal</span> keyword:</p> </span><span class="cx"> <&|formatting.myt:code &> </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemyansisqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/ansisql.py (1094 => 1095)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/ansisql.py 2006-03-04 20:23:37 UTC (rev 1094) +++ sqlalchemy/trunk/lib/sqlalchemy/ansisql.py 2006-03-05 20:31:44 UTC (rev 1095) </span><span class="lines">@@ -15,6 +15,18 @@ </span><span class="cx"> from sqlalchemy.util import * </span><span class="cx"> import string, re </span><span class="cx"> </span><ins>+ANSI_FUNCS = HashSet([ +'CURRENT_TIME', +'CURRENT_TIMESTAMP', +'CURRENT_DATE', +'LOCAL_TIME', +'LOCAL_TIMESTAMP', +'CURRENT_USER', +'SESSION_USER', +'USER' +]) + + </ins><span class="cx"> def engine(**params): </span><span class="cx"> return ANSISQLEngine(**params) </span><span class="cx"> </span><span class="lines">@@ -57,6 +69,7 @@ </span><span class="cx"> self.select_stack = [] </span><span class="cx"> self.typemap = typemap or {} </span><span class="cx"> self.isinsert = False </span><ins>+ self.isupdate = False </ins><span class="cx"> self.bindtemplate = ":%s" </span><span class="cx"> if engine is not None: </span><span class="cx"> self.paramstyle = engine.paramstyle </span><span class="lines">@@ -89,7 +102,7 @@ </span><span class="cx"> self.strings[self.statement] = re.sub(match, getnum, self.strings[self.statement]) </span><span class="cx"> </span><span class="cx"> def get_from_text(self, obj): </span><del>- return self.froms[obj] </del><ins>+ return self.froms.get(obj, None) </ins><span class="cx"> </span><span class="cx"> def get_str(self, obj): </span><span class="cx"> return self.strings[obj] </span><span class="lines">@@ -158,6 +171,11 @@ </span><span class="cx"> else: </span><span class="cx"> return parameters </span><span class="cx"> </span><ins>+ def default_from(self): + """called when a SELECT statement has no froms, and no FROM clause is to be appended. + gives Oracle a chance to tack on a "FROM DUAL" to the string output. """ + return "" + </ins><span class="cx"> def visit_label(self, label): </span><span class="cx"> if len(self.select_stack): </span><span class="cx"> self.typemap.setdefault(label.name.lower(), label.obj.type) </span><span class="lines">@@ -211,7 +229,12 @@ </span><span class="cx"> self.strings[list] = string.join([self.get_str(c) for c in list.clauses], ', ') </span><span class="cx"> </span><span class="cx"> def visit_function(self, func): </span><del>- self.strings[func] = func.name + "(" + string.join([self.get_str(c) for c in func.clauses], ', ') + ")" </del><ins>+ if len(self.select_stack): + self.typemap.setdefault(func.name, func.type) + if func.name.upper() in ANSI_FUNCS and not len(func.clauses): + self.strings[func] = func.name + else: + self.strings[func] = func.name + "(" + string.join([self.get_str(c) for c in func.clauses], ', ') + ")" </ins><span class="cx"> </span><span class="cx"> def visit_compound_select(self, cs): </span><span class="cx"> text = string.join([self.get_str(c) for c in cs.selects], " " + cs.keyword + " ") </span><span class="lines">@@ -325,7 +348,9 @@ </span><span class="cx"> if len(froms): </span><span class="cx"> text += " \nFROM " </span><span class="cx"> text += string.join(froms, ', ') </span><del>- </del><ins>+ else: + text += self.default_from() + </ins><span class="cx"> if whereclause is not None: </span><span class="cx"> t = self.get_str(whereclause) </span><span class="cx"> if t: </span><span class="lines">@@ -384,21 +409,33 @@ </span><span class="cx"> </span><span class="cx"> def visit_insert_column_default(self, column, default): </span><span class="cx"> """called when visiting an Insert statement, for each column in the table that </span><del>- contains a ColumnDefault object.""" </del><ins>+ contains a ColumnDefault object. adds a blank 'placeholder' parameter so the + Insert gets compiled with this column's name in its column and VALUES clauses.""" </ins><span class="cx"> self.parameters.setdefault(column.key, None) </span><ins>+ + def visit_update_column_default(self, column, default): + """called when visiting an Update statement, for each column in the table that + contains a ColumnDefault object as an onupdate. adds a blank 'placeholder' parameter so the + Update gets compiled with this column's name as one of its SET clauses.""" + self.parameters.setdefault(column.key, None) </ins><span class="cx"> </span><span class="cx"> def visit_insert_sequence(self, column, sequence): </span><span class="cx"> """called when visiting an Insert statement, for each column in the table that </span><del>- contains a Sequence object.""" </del><ins>+ contains a Sequence object. Overridden by compilers that support sequences to place + a blank 'placeholder' parameter, so the Insert gets compiled with this column's + name in its column and VALUES clauses.""" </ins><span class="cx"> pass </span><span class="cx"> </span><span class="cx"> def visit_insert_column(self, column): </span><span class="cx"> """called when visiting an Insert statement, for each column in the table </span><del>- that is a NULL insert into the table""" </del><ins>+ that is a NULL insert into the table. Overridden by compilers who disallow + NULL columns being set in an Insert where there is a default value on the column + (i.e. postgres), to remove the column from the parameter list.""" </ins><span class="cx"> pass </span><span class="cx"> </span><span class="cx"> def visit_insert(self, insert_stmt): </span><del>- # set up a call for the defaults and sequences inside the table </del><ins>+ # scan the table's columns for defaults that have to be pre-set for an INSERT + # add these columns to the parameter list via visit_insert_XXX methods </ins><span class="cx"> class DefaultVisitor(schema.SchemaVisitor): </span><span class="cx"> def visit_column(s, c): </span><span class="cx"> self.visit_insert_column(c) </span><span class="lines">@@ -424,6 +461,17 @@ </span><span class="cx"> self.strings[insert_stmt] = text </span><span class="cx"> </span><span class="cx"> def visit_update(self, update_stmt): </span><ins>+ # scan the table's columns for onupdates that have to be pre-set for an UPDATE + # add these columns to the parameter list via visit_update_XXX methods + class OnUpdateVisitor(schema.SchemaVisitor): + def visit_column_onupdate(s, cd): + self.visit_update_column_default(c, cd) + vis = OnUpdateVisitor() + for c in update_stmt.table.c: + if (isinstance(c, schema.SchemaItem) and (self.parameters is None or self.parameters.get(c.key, None) is None)): + c.accept_schema_visitor(vis) + + self.isupdate = True </ins><span class="cx"> colparams = self._get_colparams(update_stmt) </span><span class="cx"> def create_param(p): </span><span class="cx"> if isinstance(p, sql.BindParamClause): </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemydatabasesoraclepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/databases/oracle.py (1094 => 1095)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/databases/oracle.py 2006-03-04 20:23:37 UTC (rev 1094) +++ sqlalchemy/trunk/lib/sqlalchemy/databases/oracle.py 2006-03-05 20:31:44 UTC (rev 1095) </span><span class="lines">@@ -209,6 +209,11 @@ </span><span class="cx"> self._use_ansi = use_ansi </span><span class="cx"> ansisql.ANSICompiler.__init__(self, statement, parameters, engine=engine, **kwargs) </span><span class="cx"> </span><ins>+ def default_from(self): + """called when a SELECT statement has no froms, and no FROM clause is to be appended. + gives Oracle a chance to tack on a "FROM DUAL" to the string output. """ + return " FROM DUAL" + </ins><span class="cx"> def visit_join(self, join): </span><span class="cx"> if self._use_ansi: </span><span class="cx"> return ansisql.ANSICompiler.visit_join(self, join) </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemydatabasespostgrespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/databases/postgres.py (1094 => 1095)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/databases/postgres.py 2006-03-04 20:23:37 UTC (rev 1094) +++ sqlalchemy/trunk/lib/sqlalchemy/databases/postgres.py 2006-03-05 20:31:44 UTC (rev 1095) </span><span class="lines">@@ -103,16 +103,6 @@ </span><span class="cx"> def get_col_spec(self): </span><span class="cx"> return "BOOLEAN" </span><span class="cx"> </span><del>-ANSI_FUNCS = util.HashSet([ -'CURRENT_TIME', -'CURRENT_TIMESTAMP', -'CURRENT_DATE', -'LOCAL_TIME', -'LOCAL_TIMESTAMP', -'CURRENT_USER', -'SESSION_USER', -'USER' -]) </del><span class="cx"> </span><span class="cx"> pg2_colspecs = { </span><span class="cx"> sqltypes.Integer : PGInteger, </span><span class="lines">@@ -283,12 +273,6 @@ </span><span class="cx"> </span><span class="cx"> class PGCompiler(ansisql.ANSICompiler): </span><span class="cx"> </span><del>- def visit_function(self, func): - # PG has a bunch of funcs that explicitly need no parenthesis - if func.name.upper() in ANSI_FUNCS and not len(func.clauses): - self.strings[func] = func.name - else: - super(PGCompiler, self).visit_function(func) </del><span class="cx"> </span><span class="cx"> def visit_insert_column(self, column): </span><span class="cx"> # Postgres advises against OID usage and turns it off in 8.1, </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemyenginepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/engine.py (1094 => 1095)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/engine.py 2006-03-04 20:23:37 UTC (rev 1094) +++ sqlalchemy/trunk/lib/sqlalchemy/engine.py 2006-03-05 20:31:44 UTC (rev 1095) </span><span class="lines">@@ -135,6 +135,12 @@ </span><span class="cx"> else: </span><span class="cx"> return None </span><span class="cx"> </span><ins>+ def get_column_onupdate(self, column): + if column.onupdate is not None: + return column.onupdate.accept_schema_visitor(self) + else: + return None + </ins><span class="cx"> def visit_passive_default(self, default): </span><span class="cx"> """passive defaults by definition return None on the app side, </span><span class="cx"> and are post-fetched to get the DB-side value""" </span><span class="lines">@@ -147,7 +153,15 @@ </span><span class="cx"> def exec_default_sql(self, default): </span><span class="cx"> c = sql.select([default.arg], engine=self.engine).compile() </span><span class="cx"> return self.proxy(str(c), c.get_params()).fetchone()[0] </span><del>- </del><ins>+ + def visit_column_onupdate(self, onupdate): + if isinstance(onupdate.arg, sql.ClauseElement): + return self.exec_default_sql(onupdate) + elif callable(onupdate.arg): + return onupdate.arg() + else: + return onupdate.arg + </ins><span class="cx"> def visit_column_default(self, default): </span><span class="cx"> if isinstance(default.arg, sql.ClauseElement): </span><span class="cx"> return self.exec_default_sql(default) </span><span class="lines">@@ -245,6 +259,13 @@ </span><span class="cx"> typeobj = typeobj() </span><span class="cx"> return typeobj </span><span class="cx"> </span><ins>+ def _func(self): + class FunctionGateway(object): + def __getattr__(s, name): + return lambda *c, **kwargs: sql.Function(name, engine=self, *c, **kwargs) + return FunctionGateway() + func = property(_func) + </ins><span class="cx"> def text(self, text, *args, **kwargs): </span><span class="cx"> """returns a sql.text() object for performing literal queries.""" </span><span class="cx"> return sql.text(text, engine=self, *args, **kwargs) </span><span class="lines">@@ -426,6 +447,15 @@ </span><span class="cx"> self.context.tcount = None </span><span class="cx"> </span><span class="cx"> def _process_defaults(self, proxy, compiled, parameters, **kwargs): </span><ins>+ """INSERT and UPDATE statements, when compiled, may have additional columns added to their + VALUES and SET lists corresponding to column defaults/onupdates that are present on the + Table object (i.e. ColumnDefault, Sequence, PassiveDefault). This method pre-execs those + DefaultGenerator objects that require pre-execution and sets their values within the + parameter list, and flags the thread-local state about + PassiveDefault objects that may require post-fetching the row after it is inserted/updated. + This method relies upon logic within the ANSISQLCompiler in its visit_insert and + visit_update methods that add the appropriate column clauses to the statement when its + being compiled, so that these parameters can be bound to the statement.""" </ins><span class="cx"> if compiled is None: return </span><span class="cx"> if getattr(compiled, "isinsert", False): </span><span class="cx"> if isinstance(parameters, list): </span><span class="lines">@@ -454,7 +484,19 @@ </span><span class="cx"> self.context.last_inserted_ids = None </span><span class="cx"> else: </span><span class="cx"> self.context.last_inserted_ids = last_inserted_ids </span><del>- </del><ins>+ elif getattr(compiled, 'isupdate', False): + if isinstance(parameters, list): + plist = parameters + else: + plist = [parameters] + drunner = self.defaultrunner(proxy) + for param in plist: + for c in compiled.statement.table.c: + if c.onupdate is not None and (not param.has_key(c.name) or param[c.name] is None): + value = drunner.get_column_onupdate(c) + if value is not None: + param[c.name] = value + </ins><span class="cx"> def lastrow_has_defaults(self): </span><span class="cx"> return self.context.lastrow_has_defaults </span><span class="cx"> </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemyschemapy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/schema.py (1094 => 1095)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/schema.py 2006-03-04 20:23:37 UTC (rev 1094) +++ sqlalchemy/trunk/lib/sqlalchemy/schema.py 2006-03-05 20:31:44 UTC (rev 1095) </span><span class="lines">@@ -364,6 +364,8 @@ </span><span class="cx"> then calls visit_column on the visitor.""" </span><span class="cx"> if self.default is not None: </span><span class="cx"> self.default.accept_schema_visitor(visitor) </span><ins>+ if self.onupdate is not None: + self.onupdate.accept_schema_visitor(visitor) </ins><span class="cx"> if self.foreign_key is not None: </span><span class="cx"> self.foreign_key.accept_schema_visitor(visitor) </span><span class="cx"> visitor.visit_column(self) </span><span class="lines">@@ -473,7 +475,10 @@ </span><span class="cx"> self.arg = arg </span><span class="cx"> def accept_schema_visitor(self, visitor): </span><span class="cx"> """calls the visit_column_default method on the given visitor.""" </span><del>- return visitor.visit_column_default(self) </del><ins>+ if self.for_update: + return visitor.visit_column_onupdate(self) + else: + return visitor.visit_column_default(self) </ins><span class="cx"> def __repr__(self): </span><span class="cx"> return "ColumnDefault(%s)" % repr(self.arg) </span><span class="cx"> </span><span class="lines">@@ -599,6 +604,9 @@ </span><span class="cx"> def visit_column_default(self, default): </span><span class="cx"> """visit a ColumnDefault.""" </span><span class="cx"> pass </span><ins>+ def visit_column_onupdate(self, onupdate): + """visit a ColumnDefault with the "for_update" flag set.""" + pass </ins><span class="cx"> def visit_sequence(self, sequence): </span><span class="cx"> """visit a Sequence.""" </span><span class="cx"> pass </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemysqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/sql.py (1094 => 1095)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/sql.py 2006-03-04 20:23:37 UTC (rev 1094) +++ sqlalchemy/trunk/lib/sqlalchemy/sql.py 2006-03-05 20:31:44 UTC (rev 1095) </span><span class="lines">@@ -762,6 +762,9 @@ </span><span class="cx"> def __init__(self, name, *clauses, **kwargs): </span><span class="cx"> self.name = name </span><span class="cx"> self.type = kwargs.get('type', sqltypes.NULLTYPE) </span><ins>+ self._engine = kwargs.get('engine', None) + if self._engine is not None: + self.type = self._engine.type_descriptor(self.type) </ins><span class="cx"> ClauseList.__init__(self, parens=True, *clauses) </span><span class="cx"> key = property(lambda self:self.name) </span><span class="cx"> def append(self, clause): </span><span class="lines">@@ -771,6 +774,8 @@ </span><span class="cx"> else: </span><span class="cx"> clause = BindParamClause(self.name, clause, shortname=self.name, type=None) </span><span class="cx"> self.clauses.append(clause) </span><ins>+ def _process_from_dict(self, data, asfrom): + data.setdefault(self, self) </ins><span class="cx"> def copy_container(self): </span><span class="cx"> clauses = [clause.copy_container() for clause in self.clauses] </span><span class="cx"> return Function(self.name, type=self.type, *clauses) </span><span class="lines">@@ -782,6 +787,10 @@ </span><span class="cx"> return BindParamClause(self.name, obj, shortname=self.name, type=self.type) </span><span class="cx"> def select(self): </span><span class="cx"> return select([self]) </span><ins>+ def scalar(self): + return select([self]).scalar() + def execute(self): + return select([self]).execute() </ins><span class="cx"> def _compare_type(self, obj): </span><span class="cx"> return self.type </span><span class="cx"> </span></span></pre></div> <a id="sqlalchemytrunktestdefaultspy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/test/defaults.py (1094 => 1095)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/test/defaults.py 2006-03-04 20:23:37 UTC (rev 1094) +++ sqlalchemy/trunk/test/defaults.py 2006-03-05 20:31:44 UTC (rev 1095) </span><span class="lines">@@ -7,11 +7,11 @@ </span><span class="cx"> import sqlalchemy </span><span class="cx"> </span><span class="cx"> db = testbase.db </span><del>- </del><ins>+testbase.echo=False </ins><span class="cx"> class DefaultTest(PersistTest): </span><span class="cx"> </span><span class="cx"> def setUpAll(self): </span><del>- global t, f, ts </del><ins>+ global t, f, ts, currenttime </ins><span class="cx"> x = {'x':50} </span><span class="cx"> def mydefault(): </span><span class="cx"> x['x'] += 1 </span><span class="lines">@@ -22,18 +22,19 @@ </span><span class="cx"> </span><span class="cx"> # select "count(1)" from the DB which returns different results </span><span class="cx"> # on different DBs </span><ins>+ currenttime = db.func.current_date(type=Date); </ins><span class="cx"> if is_oracle: </span><del>- f = select([func.count(1) + 5], engine=db, from_obj=['DUAL']).scalar() - ts = select([func.sysdate()], engine=db, from_obj=['DUAL']).scalar() - def1 = func.sysdate() </del><ins>+ ts = db.func.sysdate().scalar() + f = select([func.count(1) + 5], engine=db).scalar() + def1 = currenttime </ins><span class="cx"> def2 = text("sysdate") </span><span class="cx"> deftype = Date </span><span class="cx"> elif use_function_defaults: </span><span class="cx"> f = select([func.count(1) + 5], engine=db).scalar() </span><del>- def1 = func.current_date() </del><ins>+ def1 = currenttime </ins><span class="cx"> def2 = text("current_date") </span><span class="cx"> deftype = Date </span><del>- ts = select([func.current_date()], engine=db).scalar() </del><ins>+ ts = db.func.current_date().scalar() </ins><span class="cx"> else: </span><span class="cx"> f = select([func.count(1) + 5], engine=db).scalar() </span><span class="cx"> def1 = def2 = "3" </span><span class="lines">@@ -45,20 +46,29 @@ </span><span class="cx"> Column('col1', Integer, primary_key=True, default=mydefault), </span><span class="cx"> </span><span class="cx"> # python literal </span><del>- Column('col2', String(20), default="imthedefault"), </del><ins>+ Column('col2', String(20), default="imthedefault", onupdate="im the update"), </ins><span class="cx"> </span><span class="cx"> # preexecute expression </span><del>- Column('col3', Integer, default=func.count(1) + 5), </del><ins>+ Column('col3', Integer, default=func.count(1) + 5, onupdate=func.count(1) + 14), </ins><span class="cx"> </span><span class="cx"> # SQL-side default from sql expression </span><span class="cx"> Column('col4', deftype, PassiveDefault(def1)), </span><span class="cx"> </span><span class="cx"> # SQL-side default from literal expression </span><del>- Column('col5', deftype, PassiveDefault(def2)) </del><ins>+ Column('col5', deftype, PassiveDefault(def2)), + + # preexecute + update timestamp + Column('col6', Date, default=currenttime, onupdate=currenttime) </ins><span class="cx"> ) </span><span class="cx"> t.create() </span><span class="cx"> </span><del>- def teststandalonedefaults(self): </del><ins>+ def tearDownAll(self): + t.drop() + + def tearDown(self): + t.delete().execute() + + def teststandalone(self): </ins><span class="cx"> x = t.c.col1.default.execute() </span><span class="cx"> y = t.c.col2.default.execute() </span><span class="cx"> z = t.c.col3.default.execute() </span><span class="lines">@@ -66,18 +76,27 @@ </span><span class="cx"> self.assert_(y == 'imthedefault') </span><span class="cx"> self.assert_(z == 6) </span><span class="cx"> </span><del>- def testinsertdefaults(self): </del><ins>+ def testinsert(self): </ins><span class="cx"> t.insert().execute() </span><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><del>- </del><ins>+ + ctexec = currenttime.scalar() + self.echo("Currenttime "+ repr(ctexec)) </ins><span class="cx"> l = t.select().execute() </span><del>- self.assert_(l.fetchall() == [(51, 'imthedefault', f, ts, ts), (52, 'imthedefault', f, ts, ts), (53, 'imthedefault', f, ts, ts)]) </del><ins>+ self.assert_(l.fetchall() == [(51, 'imthedefault', f, ts, ts, ctexec), (52, 'imthedefault', f, ts, ts, ctexec), (53, 'imthedefault', f, ts, ts, ctexec)]) </ins><span class="cx"> </span><del>- def tearDownAll(self): - t.drop() - </del><ins>+ def testupdate(self): + t.insert().execute() + pk = t.engine.last_inserted_ids()[0] + t.update(t.c.col1==pk).execute(col4=None, col5=None) + ctexec = currenttime.scalar() + self.echo("Currenttime "+ repr(ctexec)) + l = t.select(t.c.col1==pk).execute() + l = l.fetchone() + self.assert_(l == (pk, 'im the update', 15, None, None, ctexec)) + </ins><span class="cx"> class SequenceTest(PersistTest): </span><span class="cx"> </span><span class="cx"> def setUpAll(self): </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-03-04 20:23:46
|
<!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>[1094] sqlalchemy/trunk/test: got column defaults to be executeable</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1094</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-03-04 14:23:37 -0600 (Sat, 04 Mar 2006)</dd> </dl> <h3>Log Message</h3> <pre>got column defaults to be executeable</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> <li><a href="#sqlalchemytrunktestdefaultspy">sqlalchemy/trunk/test/defaults.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 (1093 => 1094)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/engine.py 2006-03-04 20:20:23 UTC (rev 1093) +++ sqlalchemy/trunk/lib/sqlalchemy/engine.py 2006-03-04 20:23:37 UTC (rev 1094) </span><span class="lines">@@ -596,6 +596,17 @@ </span><span class="cx"> def _executemany(self, c, statement, parameters): </span><span class="cx"> c.executemany(statement, parameters) </span><span class="cx"> self.context.rowcount = c.rowcount </span><ins>+ + def proxy(self, statement=None, parameters=None): + executemany = parameters is not None and isinstance(parameters, list) + + if self.positional: + if executemany: + parameters = [p.values() for p in parameters] + else: + parameters = parameters.values() + + return self.execute(statement, parameters) </ins><span class="cx"> </span><span class="cx"> def log(self, msg): </span><span class="cx"> """logs a message using this SQLEngine's logger stream.""" </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemyschemapy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/schema.py (1093 => 1094)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/schema.py 2006-03-04 20:20:23 UTC (rev 1093) +++ sqlalchemy/trunk/lib/sqlalchemy/schema.py 2006-03-04 20:23:37 UTC (rev 1094) </span><span class="lines">@@ -283,6 +283,7 @@ </span><span class="cx"> self.default = kwargs.pop('default', None) </span><span class="cx"> self.index = kwargs.pop('index', None) </span><span class="cx"> self.unique = kwargs.pop('unique', None) </span><ins>+ self.onupdate = kwargs.pop('onupdate', None) </ins><span class="cx"> if self.index is not None and self.unique is not None: </span><span class="cx"> raise ArgumentError("Column may not define both index and unique") </span><span class="cx"> self._foreign_key = None </span><span class="lines">@@ -302,7 +303,7 @@ </span><span class="cx"> return "Column(%s)" % string.join( </span><span class="cx"> [repr(self.name)] + [repr(self.type)] + </span><span class="cx"> [repr(x) for x in [self.foreign_key] if x is not None] + </span><del>- ["%s=%s" % (k, repr(getattr(self, k))) for k in ['key', 'primary_key', 'nullable', 'hidden', 'default']] </del><ins>+ ["%s=%s" % (k, repr(getattr(self, k))) for k in ['key', 'primary_key', 'nullable', 'hidden', 'default', 'onupdate']] </ins><span class="cx"> , ',') </span><span class="cx"> </span><span class="cx"> def append_item(self, item): </span><span class="lines">@@ -326,6 +327,9 @@ </span><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><ins>+ if self.onupdate is not None: + self.onupdate = ColumnDefault(self.onupdate, for_update=True) + self._init_items(self.onupdate) </ins><span class="cx"> self._init_items(*self.args) </span><span class="cx"> self.args = None </span><span class="cx"> </span><span class="lines">@@ -435,17 +439,26 @@ </span><span class="cx"> </span><span class="cx"> class DefaultGenerator(SchemaItem): </span><span class="cx"> """Base class for column "default" values.""" </span><ins>+ def __init__(self, for_update=False, engine=None): + self.for_update = for_update + self.engine = engine </ins><span class="cx"> def _set_parent(self, column): </span><span class="cx"> self.column = column </span><del>- self.column.default = self </del><ins>+ if self.engine is None: + self.engine = column.table.engine + if self.for_update: + self.column.onupdate = self + else: + self.column.default = self </ins><span class="cx"> def execute(self): </span><del>- return self.accept_schema_visitor(self.engine.defaultrunner(self.engine.execute)) </del><ins>+ return self.accept_schema_visitor(self.engine.defaultrunner(self.engine.proxy)) </ins><span class="cx"> def __repr__(self): </span><span class="cx"> return "DefaultGenerator()" </span><span class="cx"> </span><span class="cx"> class PassiveDefault(DefaultGenerator): </span><span class="cx"> """a default that takes effect on the database side""" </span><del>- def __init__(self, arg): </del><ins>+ def __init__(self, arg, **kwargs): + super(PassiveDefault, self).__init__(**kwargs) </ins><span class="cx"> self.arg = arg </span><span class="cx"> def accept_schema_visitor(self, visitor): </span><span class="cx"> return visitor.visit_passive_default(self) </span><span class="lines">@@ -455,7 +468,8 @@ </span><span class="cx"> class ColumnDefault(DefaultGenerator): </span><span class="cx"> """A plain default value on a column. this could correspond to a constant, </span><span class="cx"> a callable function, or a SQL clause.""" </span><del>- def __init__(self, arg): </del><ins>+ def __init__(self, arg, **kwargs): + super(ColumnDefault, self).__init__(**kwargs) </ins><span class="cx"> self.arg = arg </span><span class="cx"> def accept_schema_visitor(self, visitor): </span><span class="cx"> """calls the visit_column_default method on the given visitor.""" </span><span class="lines">@@ -465,12 +479,12 @@ </span><span class="cx"> </span><span class="cx"> class Sequence(DefaultGenerator): </span><span class="cx"> """represents a sequence, which applies to Oracle and Postgres databases.""" </span><del>- def __init__(self, name, start = None, increment = None, optional=False, engine=None): </del><ins>+ def __init__(self, name, start = None, increment = None, optional=False, **kwargs): + super(Sequence, self).__init__(**kwargs) </ins><span class="cx"> self.name = name </span><span class="cx"> self.start = start </span><span class="cx"> self.increment = increment </span><span class="cx"> self.optional=optional </span><del>- self.engine = engine </del><span class="cx"> def __repr__(self): </span><span class="cx"> return "Sequence(%s)" % string.join( </span><span class="cx"> [repr(self.name)] + </span><span class="lines">@@ -479,8 +493,6 @@ </span><span class="cx"> def _set_parent(self, column): </span><span class="cx"> super(Sequence, self)._set_parent(column) </span><span class="cx"> column.sequence = self </span><del>- if self.engine is None: - self.engine = column.table.engine </del><span class="cx"> def create(self): </span><span class="cx"> self.engine.create(self) </span><span class="cx"> return self </span></span></pre></div> <a id="sqlalchemytrunktestdefaultspy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/test/defaults.py (1093 => 1094)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/test/defaults.py 2006-03-04 20:20:23 UTC (rev 1093) +++ sqlalchemy/trunk/test/defaults.py 2006-03-04 20:23:37 UTC (rev 1094) </span><span class="lines">@@ -10,7 +10,8 @@ </span><span class="cx"> </span><span class="cx"> class DefaultTest(PersistTest): </span><span class="cx"> </span><del>- def testdefaults(self): </del><ins>+ def setUpAll(self): + global t, f, ts </ins><span class="cx"> x = {'x':50} </span><span class="cx"> def mydefault(): </span><span class="cx"> x['x'] += 1 </span><span class="lines">@@ -56,17 +57,27 @@ </span><span class="cx"> Column('col5', deftype, PassiveDefault(def2)) </span><span class="cx"> ) </span><span class="cx"> t.create() </span><del>- try: - t.insert().execute() - self.assert_(t.engine.lastrow_has_defaults()) - t.insert().execute() - t.insert().execute() </del><ins>+ + def teststandalonedefaults(self): + x = t.c.col1.default.execute() + y = t.c.col2.default.execute() + z = t.c.col3.default.execute() + self.assert_(50 <= x <= 57) + self.assert_(y == 'imthedefault') + self.assert_(z == 6) </ins><span class="cx"> </span><del>- l = t.select().execute() - self.assert_(l.fetchall() == [(51, 'imthedefault', f, ts, ts), (52, 'imthedefault', f, ts, ts), (53, 'imthedefault', f, ts, ts)]) - finally: - t.drop() </del><ins>+ def testinsertdefaults(self): + t.insert().execute() + self.assert_(t.engine.lastrow_has_defaults()) + t.insert().execute() + t.insert().execute() + + l = t.select().execute() + self.assert_(l.fetchall() == [(51, 'imthedefault', f, ts, ts), (52, 'imthedefault', f, ts, ts), (53, 'imthedefault', f, ts, ts)]) </ins><span class="cx"> </span><ins>+ def tearDownAll(self): + t.drop() + </ins><span class="cx"> class SequenceTest(PersistTest): </span><span class="cx"> </span><span class="cx"> def setUpAll(self): </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-03-04 20:20:30
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head><style type="text/css"><!-- #msg dl { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; } #msg dt { float: left; width: 6em; font-weight: bold; } #msg dt:after { content:':';} #msg dl, #msg dt, #msg ul, #msg li { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; } #msg dl a { font-weight: bold} #msg dl a:link { color:#fc3; } #msg dl a:active { color:#ff0; } #msg dl a:visited { color:#cc6; } h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; } #msg pre { overflow: auto; background: #ffc; border: 1px #fc0 solid; padding: 6px; } #msg ul, pre { overflow: auto; } #patch { width: 100%; } #patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;} #patch .propset h4, #patch .binary h4 {margin:0;} #patch pre {padding:0;line-height:1.2em;margin:0;} #patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;} #patch .propset .diff, #patch .binary .diff {padding:10px 0;} #patch span {display:block;padding:0 10px;} #patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;} #patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;} #patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;} #patch .lines, .info {color:#888;background:#fff;} --></style> <title>[1093] sqlalchemy/trunk/lib/sqlalchemy/attributes.py: added public-friendly setattr_clean and append_clean</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1093</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-03-04 14:20:23 -0600 (Sat, 04 Mar 2006)</dd> </dl> <h3>Log Message</h3> <pre>added public-friendly setattr_clean and append_clean</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunklibsqlalchemyattributespy">sqlalchemy/trunk/lib/sqlalchemy/attributes.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunklibsqlalchemyattributespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/attributes.py (1092 => 1093)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/attributes.py 2006-03-04 19:29:05 UTC (rev 1092) +++ sqlalchemy/trunk/lib/sqlalchemy/attributes.py 2006-03-04 20:20:23 UTC (rev 1093) </span><span class="lines">@@ -50,7 +50,15 @@ </span><span class="cx"> return self.manager.get_list_attribute(obj, self.key) </span><span class="cx"> else: </span><span class="cx"> return self.manager.get_attribute(obj, self.key) </span><del>- </del><ins>+ def setattr_clean(self, obj, value): + """sets an attribute on an object without triggering a history event""" + h = self.manager.get_history(obj, self.key) + h.setattr_clean(value) + def append_clean(self, obj, value): + """appends a value to a list-based attribute without triggering a history event.""" + h = self.manager.get_history(obj, self.key) + h.append_nohistory(value) + </ins><span class="cx"> class PropHistory(object): </span><span class="cx"> """Used by AttributeManager to track the history of a scalar attribute </span><span class="cx"> on an object instance. This is the "scalar history container" object. </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-03-04 19:30:44
|
<!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>[1091] sqlalchemy/trunk/test: making sequences, column defaults independently executeable</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1091</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-03-04 13:26:23 -0600 (Sat, 04 Mar 2006)</dd> </dl> <h3>Log Message</h3> <pre>making sequences, column defaults independently executeable</pre> <h3>Modified Paths</h3> <ul> <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="#sqlalchemytrunklibsqlalchemyschemapy">sqlalchemy/trunk/lib/sqlalchemy/schema.py</a></li> <li><a href="#sqlalchemytrunktestquerypy">sqlalchemy/trunk/test/query.py</a></li> <li><a href="#sqlalchemytrunktestsequencepy">sqlalchemy/trunk/test/sequence.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 (1090 => 1091)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/databases/postgres.py 2006-03-04 18:53:35 UTC (rev 1090) +++ sqlalchemy/trunk/lib/sqlalchemy/databases/postgres.py 2006-03-04 19:26:23 UTC (rev 1091) </span><span class="lines">@@ -218,7 +218,7 @@ </span><span class="cx"> def schemadropper(self, **params): </span><span class="cx"> return PGSchemaDropper(self, **params) </span><span class="cx"> </span><del>- def defaultrunner(self, proxy): </del><ins>+ def defaultrunner(self, proxy=None): </ins><span class="cx"> return PGDefaultRunner(self, proxy) </span><span class="cx"> </span><span class="cx"> def get_default_schema_name(self): </span><span class="lines">@@ -346,7 +346,7 @@ </span><span class="cx"> self.execute() </span><span class="cx"> </span><span class="cx"> class PGDefaultRunner(ansisql.ANSIDefaultRunner): </span><del>- def get_column_default(self, column): </del><ins>+ def get_column_default(self, column, isinsert=True): </ins><span class="cx"> if column.primary_key: </span><span class="cx"> # passive defaults on primary keys have to be overridden </span><span class="cx"> if isinstance(column.default, schema.PassiveDefault): </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemyenginepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/engine.py (1090 => 1091)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/engine.py 2006-03-04 18:53:35 UTC (rev 1090) +++ sqlalchemy/trunk/lib/sqlalchemy/engine.py 2006-03-04 19:26:23 UTC (rev 1091) </span><span class="lines">@@ -265,7 +265,7 @@ </span><span class="cx"> """ </span><span class="cx"> raise NotImplementedError() </span><span class="cx"> </span><del>- def defaultrunner(self, proxy): </del><ins>+ def defaultrunner(self, proxy=None): </ins><span class="cx"> """Returns a schema.SchemaVisitor instance that can execute the default values on a column. </span><span class="cx"> The base class for this visitor is the DefaultRunner class inside this module. </span><span class="cx"> This visitor will typically only receive schema.DefaultGenerator schema objects. The given </span><span class="lines">@@ -275,7 +275,7 @@ </span><span class="cx"> </span><span class="cx"> defaultrunner is called within the context of the execute_compiled() method.""" </span><span class="cx"> return DefaultRunner(self, proxy) </span><del>- </del><ins>+ </ins><span class="cx"> def compiler(self, statement, parameters): </span><span class="cx"> """returns a sql.ClauseVisitor which will produce a string representation of the given </span><span class="cx"> ClauseElement and parameter dictionary. This object is usually a subclass of </span><span class="lines">@@ -529,7 +529,7 @@ </span><span class="cx"> self.post_exec(proxy, compiled, parameters, **kwargs) </span><span class="cx"> return ResultProxy(cursor, self, typemap=compiled.typemap) </span><span class="cx"> </span><del>- def execute(self, statement, parameters, connection=None, cursor=None, echo=None, typemap=None, commit=False, return_raw=False, **kwargs): </del><ins>+ def execute(self, statement, parameters=None, connection=None, cursor=None, echo=None, typemap=None, commit=False, return_raw=False, **kwargs): </ins><span class="cx"> """executes the given string-based SQL statement with the given parameters. </span><span class="cx"> </span><span class="cx"> The parameters can be a dictionary or a list, or a list of dictionaries or lists, depending </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemyschemapy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/schema.py (1090 => 1091)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/schema.py 2006-03-04 18:53:35 UTC (rev 1090) +++ sqlalchemy/trunk/lib/sqlalchemy/schema.py 2006-03-04 19:26:23 UTC (rev 1091) </span><span class="lines">@@ -434,11 +434,12 @@ </span><span class="cx"> self.parent.table.foreign_keys.append(self) </span><span class="cx"> </span><span class="cx"> class DefaultGenerator(SchemaItem): </span><del>- """Base class for column "default" values, which can be a plain default - or a Sequence.""" </del><ins>+ """Base class for column "default" values.""" </ins><span class="cx"> def _set_parent(self, column): </span><span class="cx"> self.column = column </span><span class="cx"> self.column.default = self </span><ins>+ def execute(self): + return self.accept_schema_visitor(self.engine.defaultrunner(self.engine.execute)) </ins><span class="cx"> def __repr__(self): </span><span class="cx"> return "DefaultGenerator()" </span><span class="cx"> </span><span class="lines">@@ -464,17 +465,27 @@ </span><span class="cx"> </span><span class="cx"> class Sequence(DefaultGenerator): </span><span class="cx"> """represents a sequence, which applies to Oracle and Postgres databases.""" </span><del>- def __init__(self, name, start = None, increment = None, optional=False): </del><ins>+ def __init__(self, name, start = None, increment = None, optional=False, engine=None): </ins><span class="cx"> self.name = name </span><span class="cx"> self.start = start </span><span class="cx"> self.increment = increment </span><span class="cx"> self.optional=optional </span><ins>+ self.engine = engine </ins><span class="cx"> def __repr__(self): </span><span class="cx"> return "Sequence(%s)" % string.join( </span><span class="cx"> [repr(self.name)] + </span><span class="cx"> ["%s=%s" % (k, repr(getattr(self, k))) for k in ['start', 'increment', 'optional']] </span><span class="cx"> , ',') </span><del>- </del><ins>+ def _set_parent(self, column): + super(Sequence, self)._set_parent(column) + column.sequence = self + if self.engine is None: + self.engine = column.table.engine + def create(self): + self.engine.create(self) + return self + def drop(self): + self.engine.drop(self) </ins><span class="cx"> def accept_schema_visitor(self, visitor): </span><span class="cx"> """calls the visit_seauence method on the given visitor.""" </span><span class="cx"> return visitor.visit_sequence(self) </span></span></pre></div> <a id="sqlalchemytrunktestquerypy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/test/query.py (1090 => 1091)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/test/query.py 2006-03-04 18:53:35 UTC (rev 1090) +++ sqlalchemy/trunk/test/query.py 2006-03-04 19:26:23 UTC (rev 1091) </span><span class="lines">@@ -5,7 +5,7 @@ </span><span class="cx"> import sqlalchemy.databases.sqlite as sqllite </span><span class="cx"> </span><span class="cx"> db = testbase.db </span><del>-db.echo='debug' </del><ins>+#db.echo='debug' </ins><span class="cx"> from sqlalchemy import * </span><span class="cx"> from sqlalchemy.engine import ResultProxy, RowProxy </span><span class="cx"> </span><span class="lines">@@ -90,63 +90,7 @@ </span><span class="cx"> finally: </span><span class="cx"> test_table.drop() </span><span class="cx"> </span><del>- def testdefaults(self): - x = {'x':50} - def mydefault(): - x['x'] += 1 - return x['x'] - - use_function_defaults = db.engine.name == 'postgres' or db.engine.name == 'oracle' - is_oracle = db.engine.name == 'oracle' - - # select "count(1)" from the DB which returns different results - # on different DBs - if is_oracle: - f = select([func.count(1) + 5], engine=db, from_obj=['DUAL']).scalar() - ts = select([func.sysdate()], engine=db, from_obj=['DUAL']).scalar() - def1 = func.sysdate() - def2 = text("sysdate") - deftype = Date - elif use_function_defaults: - f = select([func.count(1) + 5], engine=db).scalar() - def1 = func.current_date() - def2 = text("current_date") - deftype = Date - ts = select([func.current_date()], engine=db).scalar() - else: - f = select([func.count(1) + 5], engine=db).scalar() - def1 = def2 = "3" - ts = 3 - deftype = Integer - - t = Table('default_test1', db, - # python function - Column('col1', Integer, primary_key=True, default=mydefault), - - # python literal - Column('col2', String(20), default="imthedefault"), - - # preexecute expression - Column('col3', Integer, default=func.count(1) + 5), - - # SQL-side default from sql expression - Column('col4', deftype, PassiveDefault(def1)), - - # SQL-side default from literal expression - Column('col5', deftype, PassiveDefault(def2)) - ) - t.create() - try: - t.insert().execute() - self.assert_(t.engine.lastrow_has_defaults()) - t.insert().execute() - t.insert().execute() </del><span class="cx"> </span><del>- l = t.select().execute() - self.assert_(l.fetchall() == [(51, 'imthedefault', f, ts, ts), (52, 'imthedefault', f, ts, ts), (53, 'imthedefault', f, ts, ts)]) - finally: - t.drop() - </del><span class="cx"> def testdelete(self): </span><span class="cx"> c = db.connection() </span><span class="cx"> </span></span></pre></div> <a id="sqlalchemytrunktestsequencepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/test/sequence.py (1090 => 1091)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/test/sequence.py 2006-03-04 18:53:35 UTC (rev 1090) +++ sqlalchemy/trunk/test/sequence.py 2006-03-04 19:26:23 UTC (rev 1091) </span><span class="lines">@@ -6,30 +6,106 @@ </span><span class="cx"> from sqlalchemy import * </span><span class="cx"> import sqlalchemy </span><span class="cx"> </span><ins>+db = testbase.db </ins><span class="cx"> </span><ins>+class DefaultTest(PersistTest): + + def testdefaults(self): + x = {'x':50} + def mydefault(): + x['x'] += 1 + return x['x'] + + use_function_defaults = db.engine.name == 'postgres' or db.engine.name == 'oracle' + is_oracle = db.engine.name == 'oracle' + + # select "count(1)" from the DB which returns different results + # on different DBs + if is_oracle: + f = select([func.count(1) + 5], engine=db, from_obj=['DUAL']).scalar() + ts = select([func.sysdate()], engine=db, from_obj=['DUAL']).scalar() + def1 = func.sysdate() + def2 = text("sysdate") + deftype = Date + elif use_function_defaults: + f = select([func.count(1) + 5], engine=db).scalar() + def1 = func.current_date() + def2 = text("current_date") + deftype = Date + ts = select([func.current_date()], engine=db).scalar() + else: + f = select([func.count(1) + 5], engine=db).scalar() + def1 = def2 = "3" + ts = 3 + deftype = Integer + + t = Table('default_test1', db, + # python function + Column('col1', Integer, primary_key=True, default=mydefault), + + # python literal + Column('col2', String(20), default="imthedefault"), + + # preexecute expression + Column('col3', Integer, default=func.count(1) + 5), + + # SQL-side default from sql expression + Column('col4', deftype, PassiveDefault(def1)), + + # SQL-side default from literal expression + Column('col5', deftype, PassiveDefault(def2)) + ) + t.create() + try: + t.insert().execute() + self.assert_(t.engine.lastrow_has_defaults()) + t.insert().execute() + t.insert().execute() + + l = t.select().execute() + self.assert_(l.fetchall() == [(51, 'imthedefault', f, ts, ts), (52, 'imthedefault', f, ts, ts), (53, 'imthedefault', f, ts, ts)]) + finally: + t.drop() + </ins><span class="cx"> class SequenceTest(PersistTest): </span><span class="cx"> </span><del>- def setUp(self): - db = sqlalchemy.engine.create_engine('postgres', {'database':'test', 'host':'127.0.0.1', 'user':'scott', 'password':'tiger'}, echo=testbase.echo) - #db = sqlalchemy.engine.create_engine('oracle', {'dsn':os.environ['DSN'], 'user':os.environ['USER'], 'password':os.environ['PASSWORD']}, echo=testbase.echo) - - self.table = Table("cartitems", db, </del><ins>+ def setUpAll(self): + if testbase.db.engine.name != 'postgres' and testbase.db.engine.name != 'oracle': + return + global cartitems + cartitems = Table("cartitems", db, </ins><span class="cx"> Column("cart_id", Integer, Sequence('cart_id_seq'), primary_key=True), </span><span class="cx"> Column("description", String(40)), </span><span class="cx"> Column("createdate", DateTime()) </span><span class="cx"> ) </span><span class="cx"> </span><del>- self.table.create() </del><ins>+ cartitems.create() </ins><span class="cx"> </span><span class="cx"> def testsequence(self): </span><del>- self.table.insert().execute(description='hi') - self.table.insert().execute(description='there') - self.table.insert().execute(description='lala') </del><ins>+ cartitems.insert().execute(description='hi') + cartitems.insert().execute(description='there') + cartitems.insert().execute(description='lala') </ins><span class="cx"> </span><del>- self.table.select().execute().fetchall() </del><ins>+ cartitems.select().execute().fetchall() </ins><span class="cx"> </span><del>- def tearDown(self): - self.table.drop() </del><ins>+ + def teststandalone(self): + s = Sequence("my_sequence", engine=db) + s.create() + try: + x =s.execute() + self.assert_(x == 1) + finally: + s.drop() + + def teststandalone2(self): + x = cartitems.c.cart_id.sequence.execute() + self.assert_(1 <= x <= 4) + + def tearDownAll(self): + if testbase.db.engine.name != 'postgres' and testbase.db.engine.name != 'oracle': + return + cartitems.drop() </ins><span class="cx"> </span><span class="cx"> if __name__ == "__main__": </span><span class="cx"> unittest.main() </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-03-04 19:29:48
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head><style type="text/css"><!-- #msg dl { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; } #msg dt { float: left; width: 6em; font-weight: bold; } #msg dt:after { content:':';} #msg dl, #msg dt, #msg ul, #msg li { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; } #msg dl a { font-weight: bold} #msg dl a:link { color:#fc3; } #msg dl a:active { color:#ff0; } #msg dl a:visited { color:#cc6; } h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; } #msg pre { overflow: auto; background: #ffc; border: 1px #fc0 solid; padding: 6px; } #msg ul, pre { overflow: auto; } #patch { width: 100%; } #patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;} #patch .propset h4, #patch .binary h4 {margin:0;} #patch pre {padding:0;line-height:1.2em;margin:0;} #patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;} #patch .propset .diff, #patch .binary .diff {padding:10px 0;} #patch span {display:block;padding:0 10px;} #patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;} #patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;} #patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;} #patch .lines, .info {color:#888;background:#fff;} --></style> <title>[1092] sqlalchemy/trunk/test: moved name to 'defaults', going to put more default stuff in</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1092</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-03-04 13:29:05 -0600 (Sat, 04 Mar 2006)</dd> </dl> <h3>Log Message</h3> <pre>moved name to 'defaults', going to put more default stuff in</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunktestalltestspy">sqlalchemy/trunk/test/alltests.py</a></li> </ul> <h3>Added Paths</h3> <ul> <li><a href="#sqlalchemytrunktestdefaultspy">sqlalchemy/trunk/test/defaults.py</a></li> </ul> <h3>Removed Paths</h3> <ul> <li><a href="#sqlalchemytrunktestsequencepy">sqlalchemy/trunk/test/sequence.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunktestalltestspy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/test/alltests.py (1091 => 1092)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/test/alltests.py 2006-03-04 19:26:23 UTC (rev 1091) +++ sqlalchemy/trunk/test/alltests.py 2006-03-04 19:29:05 UTC (rev 1092) </span><span class="lines">@@ -27,8 +27,8 @@ </span><span class="cx"> # assorted round-trip tests </span><span class="cx"> 'query', </span><span class="cx"> </span><del>- # sequences (postgres/oracle) - 'sequence', </del><ins>+ # defaults, sequences (postgres/oracle) + 'defaults', </ins><span class="cx"> </span><span class="cx"> # ORM selecting </span><span class="cx"> 'mapper', </span></span></pre></div> <a id="sqlalchemytrunktestdefaultspyfromrev1091sqlalchemytrunktestsequencepy"></a> <div class="copfile"><h4>Copied: sqlalchemy/trunk/test/defaults.py (from rev 1091, sqlalchemy/trunk/test/sequence.py) ( => )</h4> <pre class="diff"><span> <span class="info">Deleted: sqlalchemy/trunk/test/sequence.py =================================================================== </span><del>--- sqlalchemy/trunk/test/sequence.py 2006-03-04 19:26:23 UTC (rev 1091) </del><ins>+++ sqlalchemy/trunk/test/sequence.py 2006-03-04 19:29:05 UTC (rev 1092) </ins><span class="lines">@@ -1,111 +0,0 @@ </span><del>-from testbase import PersistTest -import sqlalchemy.util as util -import unittest, sys, os -import sqlalchemy.schema as schema -import testbase -from sqlalchemy import * -import sqlalchemy - -db = testbase.db - -class DefaultTest(PersistTest): - - def testdefaults(self): - x = {'x':50} - def mydefault(): - x['x'] += 1 - return x['x'] - - use_function_defaults = db.engine.name == 'postgres' or db.engine.name == 'oracle' - is_oracle = db.engine.name == 'oracle' - - # select "count(1)" from the DB which returns different results - # on different DBs - if is_oracle: - f = select([func.count(1) + 5], engine=db, from_obj=['DUAL']).scalar() - ts = select([func.sysdate()], engine=db, from_obj=['DUAL']).scalar() - def1 = func.sysdate() - def2 = text("sysdate") - deftype = Date - elif use_function_defaults: - f = select([func.count(1) + 5], engine=db).scalar() - def1 = func.current_date() - def2 = text("current_date") - deftype = Date - ts = select([func.current_date()], engine=db).scalar() - else: - f = select([func.count(1) + 5], engine=db).scalar() - def1 = def2 = "3" - ts = 3 - deftype = Integer - - t = Table('default_test1', db, - # python function - Column('col1', Integer, primary_key=True, default=mydefault), - - # python literal - Column('col2', String(20), default="imthedefault"), - - # preexecute expression - Column('col3', Integer, default=func.count(1) + 5), - - # SQL-side default from sql expression - Column('col4', deftype, PassiveDefault(def1)), - - # SQL-side default from literal expression - Column('col5', deftype, PassiveDefault(def2)) - ) - t.create() - try: - t.insert().execute() - self.assert_(t.engine.lastrow_has_defaults()) - t.insert().execute() - t.insert().execute() - - l = t.select().execute() - self.assert_(l.fetchall() == [(51, 'imthedefault', f, ts, ts), (52, 'imthedefault', f, ts, ts), (53, 'imthedefault', f, ts, ts)]) - finally: - t.drop() - -class SequenceTest(PersistTest): - - def setUpAll(self): - if testbase.db.engine.name != 'postgres' and testbase.db.engine.name != 'oracle': - return - global cartitems - cartitems = Table("cartitems", db, - Column("cart_id", Integer, Sequence('cart_id_seq'), primary_key=True), - Column("description", String(40)), - Column("createdate", DateTime()) - ) - - cartitems.create() - - def testsequence(self): - cartitems.insert().execute(description='hi') - cartitems.insert().execute(description='there') - cartitems.insert().execute(description='lala') - - cartitems.select().execute().fetchall() - - - def teststandalone(self): - s = Sequence("my_sequence", engine=db) - s.create() - try: - x =s.execute() - self.assert_(x == 1) - finally: - s.drop() - - def teststandalone2(self): - x = cartitems.c.cart_id.sequence.execute() - self.assert_(1 <= x <= 4) - - def tearDownAll(self): - if testbase.db.engine.name != 'postgres' and testbase.db.engine.name != 'oracle': - return - cartitems.drop() - -if __name__ == "__main__": - unittest.main() </del></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-03-04 18:53:48
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head><style type="text/css"><!-- #msg dl { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; } #msg dt { float: left; width: 6em; font-weight: bold; } #msg dt:after { content:':';} #msg dl, #msg dt, #msg ul, #msg li { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; } #msg dl a { font-weight: bold} #msg dl a:link { color:#fc3; } #msg dl a:active { color:#ff0; } #msg dl a:visited { color:#cc6; } h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; } #msg pre { overflow: auto; background: #ffc; border: 1px #fc0 solid; padding: 6px; } #msg ul, pre { overflow: auto; } #patch { width: 100%; } #patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;} #patch .propset h4, #patch .binary h4 {margin:0;} #patch pre {padding:0;line-height:1.2em;margin:0;} #patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;} #patch .propset .diff, #patch .binary .diff {padding:10px 0;} #patch span {display:block;padding:0 10px;} #patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;} #patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;} #patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;} #patch .lines, .info {color:#888;background:#fff;} --></style> <title>[1090] sqlalchemy/trunk/test: removed the dependency of ANSICompiler on SQLEngine.</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1090</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-03-04 12:53:35 -0600 (Sat, 04 Mar 2006)</dd> </dl> <h3>Log Message</h3> <pre>removed the dependency of ANSICompiler on SQLEngine. you can now make ANSICompilers and compile SQL with no engine at all.</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunklibsqlalchemyansisqlpy">sqlalchemy/trunk/lib/sqlalchemy/ansisql.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemydatabasesfirebirdpy">sqlalchemy/trunk/lib/sqlalchemy/databases/firebird.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemydatabasesinformation_schemapy">sqlalchemy/trunk/lib/sqlalchemy/databases/information_schema.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemydatabasesmysqlpy">sqlalchemy/trunk/lib/sqlalchemy/databases/mysql.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemydatabasesoraclepy">sqlalchemy/trunk/lib/sqlalchemy/databases/oracle.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemydatabasespostgrespy">sqlalchemy/trunk/lib/sqlalchemy/databases/postgres.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemydatabasessqlitepy">sqlalchemy/trunk/lib/sqlalchemy/databases/sqlite.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemyenginepy">sqlalchemy/trunk/lib/sqlalchemy/engine.py</a></li> <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="sqlalchemytrunklibsqlalchemyansisqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/ansisql.py (1089 => 1090)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/ansisql.py 2006-03-04 17:46:08 UTC (rev 1089) +++ sqlalchemy/trunk/lib/sqlalchemy/ansisql.py 2006-03-04 18:53:35 UTC (rev 1090) </span><span class="lines">@@ -27,7 +27,7 @@ </span><span class="cx"> return ANSISchemaDropper(self, **params) </span><span class="cx"> </span><span class="cx"> def compiler(self, statement, parameters, **kwargs): </span><del>- return ANSICompiler(self, statement, parameters, **kwargs) </del><ins>+ return ANSICompiler(statement, parameters, engine=self, **kwargs) </ins><span class="cx"> </span><span class="cx"> def connect_args(self): </span><span class="cx"> return ([],{}) </span><span class="lines">@@ -37,7 +37,7 @@ </span><span class="cx"> </span><span class="cx"> class ANSICompiler(sql.Compiled): </span><span class="cx"> """default implementation of Compiled, which compiles ClauseElements into ANSI-compliant SQL strings.""" </span><del>- def __init__(self, engine, statement, parameters=None, typemap=None, **kwargs): </del><ins>+ def __init__(self, statement, parameters=None, typemap=None, engine=None, positional=None, paramstyle=None, **kwargs): </ins><span class="cx"> """constructs a new ANSICompiler object. </span><span class="cx"> </span><span class="cx"> engine - SQLEngine to compile against </span><span class="lines">@@ -49,7 +49,7 @@ </span><span class="cx"> key/value pairs when the Compiled is executed, and also may affect the </span><span class="cx"> actual compilation, as in the case of an INSERT where the actual columns </span><span class="cx"> inserted will correspond to the keys present in the parameters.""" </span><del>- sql.Compiled.__init__(self, engine, statement, parameters) </del><ins>+ sql.Compiled.__init__(self, statement, parameters, engine=engine) </ins><span class="cx"> self.binds = {} </span><span class="cx"> self.froms = {} </span><span class="cx"> self.wheres = {} </span><span class="lines">@@ -57,19 +57,31 @@ </span><span class="cx"> self.select_stack = [] </span><span class="cx"> self.typemap = typemap or {} </span><span class="cx"> self.isinsert = False </span><ins>+ self.bindtemplate = ":%s" + if engine is not None: + self.paramstyle = engine.paramstyle + self.positional = engine.positional + else: + self.positional = False + self.paramstyle = 'named' </ins><span class="cx"> </span><span class="cx"> def after_compile(self): </span><del>- if self.engine.positional: </del><ins>+ # this re will search for params like :param + # it has a negative lookbehind for an extra ':' so that it doesnt match + # postgres '::text' tokens + match = r'(?<!:):([\w_]+)' + if self.paramstyle=='pyformat': + self.strings[self.statement] = re.sub(match, lambda m:'%(' + m.group(1) +')s', self.strings[self.statement]) + elif self.positional: </ins><span class="cx"> self.positiontup = [] </span><del>- match = r'%\(([\w_]+)\)s' </del><span class="cx"> params = re.finditer(match, self.strings[self.statement]) </span><span class="cx"> for p in params: </span><span class="cx"> self.positiontup.append(p.group(1)) </span><del>- if self.engine.paramstyle=='qmark': </del><ins>+ if self.paramstyle=='qmark': </ins><span class="cx"> self.strings[self.statement] = re.sub(match, '?', self.strings[self.statement]) </span><del>- elif self.engine.paramstyle=='format': </del><ins>+ elif self.paramstyle=='format': </ins><span class="cx"> self.strings[self.statement] = re.sub(match, '%s', self.strings[self.statement]) </span><del>- elif self.engine.paramstyle=='numeric': </del><ins>+ elif self.paramstyle=='numeric': </ins><span class="cx"> i = [0] </span><span class="cx"> def getnum(x): </span><span class="cx"> i[0] += 1 </span><span class="lines">@@ -104,28 +116,33 @@ </span><span class="cx"> bindparams = {} </span><span class="cx"> bindparams.update(params) </span><span class="cx"> </span><del>- if self.engine.positional: </del><ins>+ if self.positional: </ins><span class="cx"> d = OrderedDict() </span><span class="cx"> for k in self.positiontup: </span><span class="cx"> b = self.binds[k] </span><del>- d[k] = b.typeprocess(b.value, self.engine) </del><ins>+ if self.engine is not None: + d[k] = b.typeprocess(b.value, self.engine) + else: + d[k] = b.value </ins><span class="cx"> else: </span><span class="cx"> d = {} </span><span class="cx"> for b in self.binds.values(): </span><del>- d[b.key] = b.typeprocess(b.value, self.engine) </del><ins>+ if self.engine is not None: + d[b.key] = b.typeprocess(b.value, self.engine) + else: + d[b.key] = b.value </ins><span class="cx"> </span><span class="cx"> for key, value in bindparams.iteritems(): </span><span class="cx"> try: </span><span class="cx"> b = self.binds[key] </span><span class="cx"> except KeyError: </span><span class="cx"> continue </span><del>- d[b.key] = b.typeprocess(value, self.engine) </del><ins>+ if self.engine is not None: + d[b.key] = b.typeprocess(value, self.engine) + else: + d[b.key] = value </ins><span class="cx"> </span><span class="cx"> return d </span><del>- if self.engine.positional: - return d.values() - else: - return d </del><span class="cx"> </span><span class="cx"> def get_named_params(self, parameters): </span><span class="cx"> """given the results of the get_params method, returns the parameters </span><span class="lines">@@ -133,8 +150,7 @@ </span><span class="cx"> same dictionary. For a positional paramstyle, the given parameters are </span><span class="cx"> assumed to be in list format and are converted back to a dictionary. </span><span class="cx"> """ </span><del>-# return parameters - if self.engine.positional: </del><ins>+ if self.positional: </ins><span class="cx"> p = {} </span><span class="cx"> for i in range(0, len(self.positiontup)): </span><span class="cx"> p[self.positiontup[i]] = parameters[i] </span><span class="lines">@@ -231,7 +247,7 @@ </span><span class="cx"> self.strings[bindparam] = self.bindparam_string(key) </span><span class="cx"> </span><span class="cx"> def bindparam_string(self, name): </span><del>- return self.engine.bindtemplate % name </del><ins>+ return self.bindtemplate % name </ins><span class="cx"> </span><span class="cx"> def visit_alias(self, alias): </span><span class="cx"> self.froms[alias] = self.get_from_text(alias.original) + " AS " + alias.name </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemydatabasesfirebirdpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/databases/firebird.py (1089 => 1090)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/databases/firebird.py 2006-03-04 17:46:08 UTC (rev 1089) +++ sqlalchemy/trunk/lib/sqlalchemy/databases/firebird.py 2006-03-04 18:53:35 UTC (rev 1090) </span><span class="lines">@@ -102,7 +102,7 @@ </span><span class="cx"> return self.context.last_inserted_ids </span><span class="cx"> </span><span class="cx"> def compiler(self, statement, bindparams, **kwargs): </span><del>- return FBCompiler(self, statement, bindparams, use_ansi=self._use_ansi, **kwargs) </del><ins>+ return FBCompiler(statement, bindparams, engine=self, use_ansi=self._use_ansi, **kwargs) </ins><span class="cx"> </span><span class="cx"> def schemagenerator(self, **params): </span><span class="cx"> return FBSchemaGenerator(self, **params) </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemydatabasesinformation_schemapy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/databases/information_schema.py (1089 => 1090)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/databases/information_schema.py 2006-03-04 17:46:08 UTC (rev 1089) +++ sqlalchemy/trunk/lib/sqlalchemy/databases/information_schema.py 2006-03-04 18:53:35 UTC (rev 1090) </span><span class="lines">@@ -132,7 +132,7 @@ </span><span class="cx"> coltype = coltype(*args) </span><span class="cx"> colargs= [] </span><span class="cx"> if default is not None: </span><del>- colargs.append(PassiveDefault(sql.text(default, escape=False))) </del><ins>+ colargs.append(PassiveDefault(sql.text(default))) </ins><span class="cx"> table.append_item(schema.Column(name, coltype, nullable=nullable, *colargs)) </span><span class="cx"> </span><span class="cx"> s = select([constraints.c.constraint_name, constraints.c.constraint_type, constraints.c.table_name, key_constraints], use_labels=True, from_obj=[constraints.join(column_constraints, column_constraints.c.constraint_name==constraints.c.constraint_name).join(key_constraints, key_constraints.c.constraint_name==column_constraints.c.constraint_name)]) </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemydatabasesmysqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/databases/mysql.py (1089 => 1090)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/databases/mysql.py 2006-03-04 17:46:08 UTC (rev 1089) +++ sqlalchemy/trunk/lib/sqlalchemy/databases/mysql.py 2006-03-04 18:53:35 UTC (rev 1090) </span><span class="lines">@@ -132,7 +132,7 @@ </span><span class="cx"> return False </span><span class="cx"> </span><span class="cx"> def compiler(self, statement, bindparams, **kwargs): </span><del>- return MySQLCompiler(self, statement, bindparams, **kwargs) </del><ins>+ return MySQLCompiler(statement, bindparams, engine=self, **kwargs) </ins><span class="cx"> </span><span class="cx"> def schemagenerator(self, **params): </span><span class="cx"> return MySQLSchemaGenerator(self, **params) </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemydatabasesoraclepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/databases/oracle.py (1089 => 1090)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/databases/oracle.py 2006-03-04 17:46:08 UTC (rev 1089) +++ sqlalchemy/trunk/lib/sqlalchemy/databases/oracle.py 2006-03-04 18:53:35 UTC (rev 1090) </span><span class="lines">@@ -151,7 +151,7 @@ </span><span class="cx"> </span><span class="cx"> colargs = [] </span><span class="cx"> if default is not None: </span><del>- colargs.append(PassiveDefault(sql.text(default, escape=False))) </del><ins>+ colargs.append(PassiveDefault(sql.text(default))) </ins><span class="cx"> </span><span class="cx"> name = name.lower() </span><span class="cx"> </span><span class="lines">@@ -207,7 +207,7 @@ </span><span class="cx"> def __init__(self, engine, statement, parameters, use_ansi = True, **kwargs): </span><span class="cx"> self._outertable = None </span><span class="cx"> self._use_ansi = use_ansi </span><del>- ansisql.ANSICompiler.__init__(self, engine, statement, parameters, **kwargs) </del><ins>+ ansisql.ANSICompiler.__init__(self, statement, parameters, engine=engine, **kwargs) </ins><span class="cx"> </span><span class="cx"> def visit_join(self, join): </span><span class="cx"> if self._use_ansi: </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemydatabasespostgrespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/databases/postgres.py (1089 => 1090)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/databases/postgres.py 2006-03-04 17:46:08 UTC (rev 1089) +++ sqlalchemy/trunk/lib/sqlalchemy/databases/postgres.py 2006-03-04 18:53:35 UTC (rev 1090) </span><span class="lines">@@ -210,7 +210,7 @@ </span><span class="cx"> return sqltypes.adapt_type(typeobj, pg1_colspecs) </span><span class="cx"> </span><span class="cx"> def compiler(self, statement, bindparams, **kwargs): </span><del>- return PGCompiler(self, statement, bindparams, **kwargs) </del><ins>+ return PGCompiler(statement, bindparams, engine=self, **kwargs) </ins><span class="cx"> </span><span class="cx"> def schemagenerator(self, **params): </span><span class="cx"> return PGSchemaGenerator(self, **params) </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemydatabasessqlitepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/databases/sqlite.py (1089 => 1090)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/databases/sqlite.py 2006-03-04 17:46:08 UTC (rev 1089) +++ sqlalchemy/trunk/lib/sqlalchemy/databases/sqlite.py 2006-03-04 18:53:35 UTC (rev 1090) </span><span class="lines">@@ -147,7 +147,7 @@ </span><span class="cx"> return ([self.filename], self.opts) </span><span class="cx"> </span><span class="cx"> def compiler(self, statement, bindparams, **kwargs): </span><del>- return SQLiteCompiler(self, statement, bindparams, **kwargs) </del><ins>+ return SQLiteCompiler(statement, bindparams, engine=self, **kwargs) </ins><span class="cx"> </span><span class="cx"> def dbapi(self): </span><span class="cx"> return sqlite </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemyenginepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/engine.py (1089 => 1090)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/engine.py 2006-03-04 17:46:08 UTC (rev 1089) +++ sqlalchemy/trunk/lib/sqlalchemy/engine.py 2006-03-04 18:53:35 UTC (rev 1090) </span><span class="lines">@@ -227,15 +227,12 @@ </span><span class="cx"> self._paramstyle = 'named' </span><span class="cx"> </span><span class="cx"> if self._paramstyle == 'named': </span><del>- self.bindtemplate = ':%s' </del><span class="cx"> self.positional=False </span><span class="cx"> elif self._paramstyle == 'pyformat': </span><del>- self.bindtemplate = "%%(%s)s" </del><span class="cx"> self.positional=False </span><span class="cx"> elif self._paramstyle == 'qmark' or self._paramstyle == 'format' or self._paramstyle == 'numeric': </span><span class="cx"> # for positional, use pyformat internally, ANSICompiler will convert </span><span class="cx"> # to appropriate character upon compilation </span><del>- self.bindtemplate = "%%(%s)s" </del><span class="cx"> self.positional = True </span><span class="cx"> else: </span><span class="cx"> raise DBAPIError("Unsupported paramstyle '%s'" % self._paramstyle) </span><span class="lines">@@ -310,8 +307,7 @@ </span><span class="cx"> instance of this engine's SQLCompiler, compiles the ClauseElement, and returns the </span><span class="cx"> newly compiled object.""" </span><span class="cx"> compiler = self.compiler(statement, parameters, **kwargs) </span><del>- statement.accept_visitor(compiler) - compiler.after_compile() </del><ins>+ compiler.compile() </ins><span class="cx"> return compiler </span><span class="cx"> </span><span class="cx"> def reflecttable(self, table): </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemysqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/sql.py (1089 => 1090)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/sql.py 2006-03-04 17:46:08 UTC (rev 1089) +++ sqlalchemy/trunk/lib/sqlalchemy/sql.py 2006-03-04 18:53:35 UTC (rev 1090) </span><span class="lines">@@ -257,11 +257,9 @@ </span><span class="cx"> object be dependent on the actual values of those bind parameters, even though it may </span><span class="cx"> reference those values as defaults.""" </span><span class="cx"> </span><del>- def __init__(self, engine, statement, parameters): </del><ins>+ def __init__(self, statement, parameters, engine=None): </ins><span class="cx"> """constructs a new Compiled object. </span><span class="cx"> </span><del>- engine - SQLEngine to compile against - </del><span class="cx"> statement - ClauseElement to be compiled </span><span class="cx"> </span><span class="cx"> parameters - optional dictionary indicating a set of bind parameters </span><span class="lines">@@ -271,10 +269,12 @@ </span><span class="cx"> will also result in the creation of new BindParamClause objects for each key </span><span class="cx"> and will also affect the generated column list in an INSERT statement and the SET </span><span class="cx"> clauses of an UPDATE statement. The keys of the parameter dictionary can </span><del>- either be the string names of columns or actual sqlalchemy.schema.Column objects.""" - self.engine = engine </del><ins>+ either be the string names of columns or ColumnClause objects. + + engine - optional SQLEngine to compile this statement against""" </ins><span class="cx"> self.parameters = parameters </span><span class="cx"> self.statement = statement </span><ins>+ self.engine = engine </ins><span class="cx"> </span><span class="cx"> def __str__(self): </span><span class="cx"> """returns the string text of the generated SQL statement.""" </span><span class="lines">@@ -290,6 +290,10 @@ </span><span class="cx"> """ </span><span class="cx"> raise NotImplementedError() </span><span class="cx"> </span><ins>+ def compile(self): + self.statement.accept_visitor(self) + self.after_compile() + </ins><span class="cx"> def execute(self, *multiparams, **params): </span><span class="cx"> """executes this compiled object using the underlying SQLEngine""" </span><span class="cx"> if len(multiparams): </span><span class="lines">@@ -367,21 +371,26 @@ </span><span class="cx"> return None </span><span class="cx"> </span><span class="cx"> engine = property(lambda s: s._find_engine(), doc="attempts to locate a SQLEngine within this ClauseElement structure, or returns None if none found.") </span><del>- - def compile(self, engine = None, parameters = None, typemap=None): </del><ins>+ + + def compile(self, engine = None, parameters = None, typemap=None, compiler=None): </ins><span class="cx"> """compiles this SQL expression using its underlying SQLEngine to produce </span><span class="cx"> a Compiled object. If no engine can be found, an ansisql engine is used. </span><span class="cx"> bindparams is a dictionary representing the default bind parameters to be used with </span><span class="cx"> the statement. """ </span><del>- if engine is None: - engine = self.engine - - if engine is None: </del><ins>+ + if compiler is None: + if engine is not None: + compiler = engine.compiler(self, parameters) + elif self.engine is not None: + compiler = self.engine.compiler(self, parameters) + + if compiler is None: </ins><span class="cx"> import sqlalchemy.ansisql as ansisql </span><del>- engine = ansisql.engine() </del><ins>+ compiler = ansisql.ANSICompiler(self, parameters=parameters, typemap=typemap) + compiler.compile() + return compiler </ins><span class="cx"> </span><del>- return engine.compile(self, parameters=parameters, typemap=typemap) - </del><span class="cx"> def __str__(self): </span><span class="cx"> return str(self.compile()) </span><span class="cx"> </span><span class="lines">@@ -638,7 +647,7 @@ </span><span class="cx"> being specified as a bind parameter via the bindparam() method, </span><span class="cx"> since it provides more information about what it is, including an optional </span><span class="cx"> type, as well as providing comparison operations.""" </span><del>- def __init__(self, text = "", engine=None, bindparams=None, typemap=None, escape=True): </del><ins>+ def __init__(self, text = "", engine=None, bindparams=None, typemap=None): </ins><span class="cx"> self.parens = False </span><span class="cx"> self._engine = engine </span><span class="cx"> self.id = id(self) </span><span class="lines">@@ -649,12 +658,10 @@ </span><span class="cx"> typemap[key] = engine.type_descriptor(typemap[key]) </span><span class="cx"> def repl(m): </span><span class="cx"> self.bindparams[m.group(1)] = bindparam(m.group(1)) </span><del>- return self.engine.bindtemplate % m.group(1) - - if escape: - self.text = re.compile(r':([\w_]+)', re.S).sub(repl, text) - else: - self.text = text </del><ins>+ return ":%s" % m.group(1) + # scan the string and search for bind parameter names, add them + # to the list of bindparams + self.text = re.compile(r'(?<!:):([\w_]+)', re.S).sub(repl, text) </ins><span class="cx"> if bindparams is not None: </span><span class="cx"> for b in bindparams: </span><span class="cx"> self.bindparams[b.key] = b </span></span></pre></div> <a id="sqlalchemytrunktestselectpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/test/select.py (1089 => 1090)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/test/select.py 2006-03-04 17:46:08 UTC (rev 1089) +++ sqlalchemy/trunk/test/select.py 2006-03-04 18:53:35 UTC (rev 1090) </span><span class="lines">@@ -57,15 +57,16 @@ </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>- c = clause.compile(parameters = params, engine=engine) </del><ins>+ print "TEST with e", engine + 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 class="cx"> if checkparams is not None: </span><span class="cx"> if isinstance(checkparams, list): </span><del>- self.assert_(c.get_params().values() == checkparams, "params dont match") </del><ins>+ self.assert_(c.get_params().values() == checkparams, "params dont match ") </ins><span class="cx"> else: </span><del>- self.assert_(c.get_params() == checkparams, "params dont match") </del><ins>+ self.assert_(c.get_params() == checkparams, "params dont match" + repr(c.get_params())) </ins><span class="cx"> </span><span class="cx"> class SelectTest(SQLTest): </span><span class="cx"> def testtableselect(self): </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-03-04 17:46:15
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head><style type="text/css"><!-- #msg dl { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; } #msg dt { float: left; width: 6em; font-weight: bold; } #msg dt:after { content:':';} #msg dl, #msg dt, #msg ul, #msg li { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; } #msg dl a { font-weight: bold} #msg dl a:link { color:#fc3; } #msg dl a:active { color:#ff0; } #msg dl a:visited { color:#cc6; } h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; } #msg pre { overflow: auto; background: #ffc; border: 1px #fc0 solid; padding: 6px; } #msg ul, pre { overflow: auto; } #patch { width: 100%; } #patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;} #patch .propset h4, #patch .binary h4 {margin:0;} #patch pre {padding:0;line-height:1.2em;margin:0;} #patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;} #patch .propset .diff, #patch .binary .diff {padding:10px 0;} #patch span {display:block;padding:0 10px;} #patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;} #patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;} #patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;} #patch .lines, .info {color:#888;background:#fff;} --></style> <title>[1089] sqlalchemy/trunk/lib/sqlalchemy/databases/oracle.py: initial table reflection support courtesy Andrija Zaric</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1089</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-03-04 11:46:08 -0600 (Sat, 04 Mar 2006)</dd> </dl> <h3>Log Message</h3> <pre>initial table reflection support courtesy Andrija Zaric</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunklibsqlalchemydatabasesoraclepy">sqlalchemy/trunk/lib/sqlalchemy/databases/oracle.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunklibsqlalchemydatabasesoraclepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/databases/oracle.py (1088 => 1089)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/databases/oracle.py 2006-03-04 17:45:19 UTC (rev 1088) +++ sqlalchemy/trunk/lib/sqlalchemy/databases/oracle.py 2006-03-04 17:46:08 UTC (rev 1089) </span><span class="lines">@@ -65,6 +65,16 @@ </span><span class="cx"> sqltypes.CHAR: OracleChar, </span><span class="cx"> } </span><span class="cx"> </span><ins>+ +ischema_names = { + 'VARCHAR2' : OracleString, + 'DATE' : OracleDateTime, + 'DATETIME' : OracleDateTime, + 'NUMBER' : OracleNumeric, + 'BLOB' : OracleBinary, + 'CLOB' : OracleText +} + </ins><span class="cx"> def engine(*args, **params): </span><span class="cx"> return OracleSQLEngine(*args, **params) </span><span class="cx"> </span><span class="lines">@@ -113,8 +123,59 @@ </span><span class="cx"> return OracleDefaultRunner(self, proxy) </span><span class="cx"> </span><span class="cx"> def reflecttable(self, table): </span><del>- raise "not implemented" </del><ins>+ c = self.execute ("select COLUMN_NAME, DATA_TYPE, DATA_LENGTH, DATA_PRECISION, DATA_SCALE, NULLABLE, DATA_DEFAULT from USER_TAB_COLUMNS where TABLE_NAME = :table_name", {'table_name':table.name}) + + while True: + row = c.fetchone() + if row is None: + break </ins><span class="cx"> </span><ins>+ (name, coltype, length, precision, scale, nullable, default) = (row[0], row[1], row[2], row[3], row[4], row[5]=='Y', row[6]) + + # INTEGER if the scale is 0 and precision is null + # NUMBER if the scale and precision are both null + # NUMBER(9,2) if the precision is 9 and the scale is 2 + # NUMBER(3) if the precision is 3 and scale is 0 + #length is ignored except for CHAR and VARCHAR2 + if coltype=='NUMBER' : + if precision is None and scale is None: + coltype = OracleNumeric + elif precision is None and scale == 0 : + coltype = OracleInteger + else : + coltype = OracleNumeric(precision, scale) + elif coltype=='CHAR' or coltype=='VARCHAR2': + coltype = ischema_names.get(coltype, OracleString)(length) + else: + coltype = ischema_names.get(coltype) + + colargs = [] + if default is not None: + colargs.append(PassiveDefault(sql.text(default, escape=False))) + + name = name.lower() + + table.append_item (schema.Column(name, coltype, nullable=nullable, *colargs)) + + + c = self.execute("""select UCC.CONSTRAINT_NAME, UCC.COLUMN_NAME, UC.CONSTRAINT_TYPE, UC.SEARCH_CONDITION, UC2.TABLE_NAME as REFERENCES_TABLE +from USER_CONS_COLUMNS UCC, USER_CONSTRAINTS UC, USER_CONSTRAINTS UC2 +where UCC.CONSTRAINT_NAME = UC.CONSTRAINT_NAME +and UC.R_CONSTRAINT_NAME = UC2.CONSTRAINT_NAME(+) +and UCC.TABLE_NAME = :table_name +order by UCC.CONSTRAINT_NAME""",{'table_name' : table.name}) + while True: + row = c.fetchone() + if row is None: + break + + (cons_name, column_name, type, search, referred_table) = row + if type=='P' : + table.c[column_name.lower()]._set_primary_key() + elif type=='R': + remotetable = Table(referred_table, referred_table.engine, autoload = True) + table.c[column_name.lower()].append_item(schema.ForeignKey(remotetable.primary_key[0])) + </ins><span class="cx"> def last_inserted_ids(self): </span><span class="cx"> return self.context.last_inserted_ids </span><span class="cx"> </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-03-04 17:45:28
|
<!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>[1088] sqlalchemy/trunk/lib/sqlalchemy/engine.py: changed default "none" parameters to check positional style</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1088</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-03-04 11:45:19 -0600 (Sat, 04 Mar 2006)</dd> </dl> <h3>Log Message</h3> <pre>changed default "none" parameters to check positional style</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunklibsqlalchemyenginepy">sqlalchemy/trunk/lib/sqlalchemy/engine.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 (1087 => 1088)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/engine.py 2006-03-04 17:41:19 UTC (rev 1087) +++ sqlalchemy/trunk/lib/sqlalchemy/engine.py 2006-03-04 17:45:19 UTC (rev 1088) </span><span class="lines">@@ -500,9 +500,6 @@ </span><span class="cx"> </span><span class="cx"> commit - if True, will automatically commit the statement after completion. """ </span><span class="cx"> </span><del>- if parameters is None: - parameters = {} - </del><span class="cx"> if connection is None: </span><span class="cx"> connection = self.connection() </span><span class="cx"> </span><span class="lines">@@ -565,9 +562,6 @@ </span><span class="cx"> </span><span class="cx"> commit - if True, will automatically commit the statement after completion. """ </span><span class="cx"> </span><del>- if parameters is None: - parameters = {} - </del><span class="cx"> if connection is None: </span><span class="cx"> connection = self.connection() </span><span class="cx"> </span><span class="lines">@@ -594,6 +588,11 @@ </span><span class="cx"> </span><span class="cx"> def _execute(self, c, statement, parameters): </span><span class="cx"> try: </span><ins>+ if parameters is None: + if self.positional: + parameters = () + else: + parameters = {} </ins><span class="cx"> c.execute(statement, parameters) </span><span class="cx"> except Exception, e: </span><span class="cx"> raise exceptions.SQLError(statement, parameters, e) </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-03-04 17:41:29
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head><style type="text/css"><!-- #msg dl { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; } #msg dt { float: left; width: 6em; font-weight: bold; } #msg dt:after { content:':';} #msg dl, #msg dt, #msg ul, #msg li { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; } #msg dl a { font-weight: bold} #msg dl a:link { color:#fc3; } #msg dl a:active { color:#ff0; } #msg dl a:visited { color:#cc6; } h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; } #msg pre { overflow: auto; background: #ffc; border: 1px #fc0 solid; padding: 6px; } #msg ul, pre { overflow: auto; } #patch { width: 100%; } #patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;} #patch .propset h4, #patch .binary h4 {margin:0;} #patch pre {padding:0;line-height:1.2em;margin:0;} #patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;} #patch .propset .diff, #patch .binary .diff {padding:10px 0;} #patch span {display:block;padding:0 10px;} #patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;} #patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;} #patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;} #patch .lines, .info {color:#888;background:#fff;} --></style> <title>[1087] sqlalchemy/trunk/lib/sqlalchemy/databases/firebird.py: firebird module initial checkin</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1087</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-03-04 11:41:19 -0600 (Sat, 04 Mar 2006)</dd> </dl> <h3>Log Message</h3> <pre>firebird module initial checkin</pre> <h3>Added Paths</h3> <ul> <li><a href="#sqlalchemytrunklibsqlalchemydatabasesfirebirdpy">sqlalchemy/trunk/lib/sqlalchemy/databases/firebird.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunklibsqlalchemydatabasesfirebirdpy"></a> <div class="addfile"><h4>Added: sqlalchemy/trunk/lib/sqlalchemy/databases/firebird.py (1086 => 1087)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/databases/firebird.py 2006-03-04 00:29:09 UTC (rev 1086) +++ sqlalchemy/trunk/lib/sqlalchemy/databases/firebird.py 2006-03-04 17:41:19 UTC (rev 1087) </span><span class="lines">@@ -0,0 +1,282 @@ </span><ins>+# firebird.py +# Copyright (C) 2005,2006 Michael Bayer mi...@zz... +# +# This module is part of SQLAlchemy and is released under +# the MIT License: http://www.opensource.org/licenses/mit-license.php + + +import sys, StringIO, string + +import sqlalchemy.sql as sql +import sqlalchemy.schema as schema +import sqlalchemy.ansisql as ansisql +from sqlalchemy import * +import sqlalchemy.types as sqltypes + +try: + import kinterbasdb +except: + kinterbasdb = None + +class FBNumeric(sqltypes.Numeric): + def get_col_spec(self): + return "NUMERIC(%(precision)s, %(length)s)" % {'precision': self.precision, 'length' : self.length} +class FBInteger(sqltypes.Integer): + def get_col_spec(self): + return "INTEGER" +class FBSmallInteger(sqltypes.Smallinteger): + def get_col_spec(self): + return "SMALLINT" +class FBDateTime(sqltypes.DateTime): + def get_col_spec(self): + return "DATE" +class FBText(sqltypes.TEXT): + def get_col_spec(self): + return "BLOB SUB_TYPE 2" +class FBString(sqltypes.String): + def get_col_spec(self): + return "VARCHAR(%(length)s)" % {'length' : self.length} +class FBChar(sqltypes.CHAR): + def get_col_spec(self): + return "CHAR(%(length)s)" % {'length' : self.length} +class FBBinary(sqltypes.Binary): + def get_col_spec(self): + return "BLOB SUB_TYPE 1" +class FBBoolean(sqltypes.Boolean): + def get_col_spec(self): + return "SMALLINT" + +colspecs = { + sqltypes.Integer : FBInteger, + sqltypes.Smallinteger : FBSmallInteger, + sqltypes.Numeric : FBNumeric, + sqltypes.Float : FBNumeric, + sqltypes.DateTime : FBDateTime, + sqltypes.Date : FBDateTime, + sqltypes.String : FBString, + sqltypes.Binary : FBBinary, + sqltypes.Boolean : FBBoolean, + sqltypes.TEXT : FBText, + sqltypes.CHAR: FBChar, +} + +def engine(*args, **params): + return FBSQLEngine(*args, **params) + +def descriptor(): + return {'name':'firebird', + 'description':'Firebird', + 'arguments':[ + ('host', 'Host Server Name', None), + ('database', 'Database Name', None), + ('user', 'Username', None), + ('password', 'Password', None) + ]} + +class FBSQLEngine(ansisql.ANSISQLEngine): + def __init__(self, opts, use_ansi = True, module = None, **params): + self._use_ansi = use_ansi + self.opts = opts or {} + if module is None: + self.module = kinterbasdb + else: + self.module = module + ansisql.ANSISQLEngine.__init__(self, **params) + + def do_commit(self, connection): + connection.commit(True) + + def do_rollback(self, connection): + connection.rollback(True) + + def dbapi(self): + return self.module + + def connect_args(self): + return [[], self.opts] + + def type_descriptor(self, typeobj): + return sqltypes.adapt_type(typeobj, colspecs) + + def last_inserted_ids(self): + return self.context.last_inserted_ids + + def compiler(self, statement, bindparams, **kwargs): + return FBCompiler(self, statement, bindparams, use_ansi=self._use_ansi, **kwargs) + + def schemagenerator(self, **params): + return FBSchemaGenerator(self, **params) + + def schemadropper(self, **params): + return FBSchemaDropper(self, **params) + + def defaultrunner(self, proxy): + return FBDefaultRunner(self, proxy) + + def reflecttable(self, table): + #TODO: map these better + column_func = { + 14 : lambda r: String(r['FLEN']), # TEXT + 7 : lambda r: Integer(), # SHORT + 8 : lambda r: Integer(), # LONG + 9 : lambda r: Float(), # QUAD + 10 : lambda r: Float(), # FLOAT + 27 : lambda r: Double(), # DOUBLE + 35 : lambda r: DateTime(), # TIMESTAMP + 37 : lambda r: String(r['FLEN']), # VARYING + 261: lambda r: TEXT(), # BLOB + 40 : lambda r: Char(r['FLEN']), # CSTRING + 12 : lambda r: Date(), # DATE + 13 : lambda r: Time(), # TIME + 16 : lambda r: Numeric(precision=r['FPREC'], length=r['FSCALE'] * -1) #INT64 + } + tblqry = """\ + SELECT DISTINCT R.RDB$FIELD_NAME AS FNAME, + R.RDB$NULL_FLAG AS NULL_FLAG, + R.RDB$FIELD_POSITION, + F.RDB$FIELD_TYPE AS FTYPE, + F.RDB$FIELD_SUB_TYPE AS STYPE, + F.RDB$FIELD_LENGTH AS FLEN, + F.RDB$FIELD_PRECISION AS FPREC, + F.RDB$FIELD_SCALE AS FSCALE + FROM RDB$RELATION_FIELDS R + JOIN RDB$FIELDS F ON R.RDB$FIELD_SOURCE=F.RDB$FIELD_NAME + WHERE F.RDB$SYSTEM_FLAG=0 and R.RDB$RELATION_NAME=? + ORDER BY R.RDB$FIELD_POSITION;""" + keyqry = """ + SELECT RC.RDB$CONSTRAINT_TYPE KEYTYPE, + RC.RDB$CONSTRAINT_NAME CNAME, + RC.RDB$INDEX_NAME INAME, + SE.RDB$FIELD_NAME SENAME, + FROM RDB$RELATION_CONSTRAINTS RC + LEFT JOIN RDB$INDEX_SEGMENTS SE + ON RC.RDB$INDEX_NAME=SE.RDB$INDEX_NAME + WHERE RC.RDB$RELATION_NAME=? AND SE.RDB$FIELD_NAME=? + """ + + #import pdb;pdb.set_trace() + # get all of the fields for this table + c = self.execute(tblqry, [table.name.upper()]) + while True: + row = c.fetchone() + if not row: break + args = [row['FNAME']] + kw = {} + # get the data types and lengths + args.append(column_func[row['FTYPE']](row)) + + # is it a foreign key (and what is it linked to) + + # is it a primary key? + + table.append_item(Column(*args, **kw)) + # does the field have indexes + + def last_inserted_ids(self): + return self.context.last_inserted_ids + + def pre_exec(self, proxy, compiled, parameters, **kwargs): + # this is just an assertion that all the primary key columns in an insert statement + # have a value set up, or have a default generator ready to go + if getattr(compiled, "isinsert", False): + if isinstance(parameters, list): + plist = parameters + else: + plist = [parameters] + for param in plist: + for primary_key in compiled.statement.table.primary_key: + if not param.has_key(primary_key.key) or param[primary_key.key] is None: + if primary_key.default is None: + raise "Column '%s.%s': Firebird primary key columns require a default value or a schema.Sequence to create ids" % (primary_key.table.name, primary_key.name) + + def _executemany(self, c, statement, parameters): + rowcount = 0 + for param in parameters: + c.execute(statement, param) + rowcount += c.rowcount + self.context.rowcount = rowcount + +class FBCompiler(ansisql.ANSICompiler): + """firebird compiler modifies the lexical structure of Select statements to work under + non-ANSI configured Firebird databases, if the use_ansi flag is False.""" + + def __init__(self, engine, statement, parameters, use_ansi = True, **kwargs): + self._outertable = None + self._use_ansi = use_ansi + ansisql.ANSICompiler.__init__(self, engine, statement, parameters, **kwargs) + + def visit_column(self, column): + if self._use_ansi: + return ansisql.ANSICompiler.visit_column(self, column) + + if column.table is self._outertable: + self.strings[column] = "%s.%s(+)" % (column.table.name, column.name) + else: + self.strings[column] = "%s.%s" % (column.table.name, column.name) + + def visit_function(self, func): + if len(func.clauses): + super(FBCompiler, self).visit_function(func) + else: + self.strings[func] = func.name + + def visit_insert(self, insert): + """inserts are required to have the primary keys be explicitly present. + mapper will by default not put them in the insert statement to comply + with autoincrement fields that require they not be present. so, + put them all in for all primary key columns.""" + for c in insert.table.primary_key: + if not self.parameters.has_key(c.key): + self.parameters[c.key] = None + return ansisql.ANSICompiler.visit_insert(self, insert) + + def visit_select_precolumns(self, select): + """ called when building a SELECT statment, position is just before column list + Firebird puts the limit and offset right after the select...thanks for adding the + visit_select_precolumns!!!""" + if select.offset: + result +=" FIRST " + select.offset + if select.limit: + result += " SKIP " + select.limit + if select.distinct: + result += " DISTINCT " + return result + + def limit_clause(self, select): + """Already taken care of in the visit_select_precolumns method.""" + return "" + +class FBSchemaGenerator(ansisql.ANSISchemaGenerator): + def get_column_specification(self, column, override_pk=False, **kwargs): + colspec = column.name + colspec += " " + column.type.get_col_spec() + default = self.get_column_default_string(column) + if default is not None: + colspec += " DEFAULT " + default + + if not column.nullable: + colspec += " NOT NULL" + if column.primary_key and not override_pk: + colspec += " PRIMARY KEY" + if column.foreign_key: + colspec += " REFERENCES %s(%s)" % (column.foreign_key.column.table.name, column.foreign_key.column.name) + return colspec + + def visit_sequence(self, sequence): + self.append("CREATE GENERATOR %s" % sequence.name) + self.execute() + +class FBSchemaDropper(ansisql.ANSISchemaDropper): + def visit_sequence(self, sequence): + self.append("DROP GENERATOR %s" % sequence.name) + self.execute() + +class FBDefaultRunner(ansisql.ANSIDefaultRunner): + def exec_default_sql(self, default): + c = sql.select([default.arg], from_obj=["rdb$database"], engine=self.engine).compile() + return self.proxy(str(c), c.get_params()).fetchone()[0] + + def visit_sequence(self, seq): + return self.proxy("SELECT gen_id(" + seq.name + ", 1) FROM rdb$database").fetchone()[0] + + </ins></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-03-04 00:29:24
|
<!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>[1086] sqlalchemy/trunk/doc/build/content/metadata.myt: mr.</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1086</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-03-03 18:29:09 -0600 (Fri, 03 Mar 2006)</dd> </dl> <h3>Log Message</h3> <pre>mr. bangerts surprise paragraph rewrite demands strike again </pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunkdocbuildcontentmetadatamyt">sqlalchemy/trunk/doc/build/content/metadata.myt</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunkdocbuildcontentmetadatamyt"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/doc/build/content/metadata.myt (1085 => 1086)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/doc/build/content/metadata.myt 2006-03-03 14:46:39 UTC (rev 1085) +++ sqlalchemy/trunk/doc/build/content/metadata.myt 2006-03-04 00:29:09 UTC (rev 1086) </span><span class="lines">@@ -179,7 +179,13 @@ </span><span class="cx"> Column("createdate", DateTime()) </span><span class="cx"> ) </span><span class="cx"> </&> </span><del>- <p>Defining a Sequence means that it will be created along with the table.create() call, and more importantly the sequence will be explicitly used when inserting new rows for this table. For databases that dont support sequences, the Sequence object has no effect. A sequence can also be specified with <span class="codeline">optional=True</span> which indicates the Sequence should only be used on a database that requires an explicit sequence (which currently is just Oracle). A database like Postgres, while it uses sequences to create primary keys, is often used via the SERIAL column option which removes the need for explicit access to the sequence.</p> </del><ins>+ <p>The Sequence is used when a Postgres or Oracle database schema defines a sequence of a specific name which must be used to create integer values. If a Sequence is not defined, Postgres will default to regular SERIAL access. Oracle currently has no default primary key method; so explicit primary key values or Sequence objects are required to insert new rows.</p> + +<p>Defining a Sequence means that it will be created along with the table.create() call, and that the sequence will be explicitly used when inserting new rows for this table, for databases that support sequences. If the Table is connected to a database that doesnt support sequences, the Sequence object is simply ignored. Note that a Sequence object is <b>entirely optional for all databases except Oracle</b>, as other databases offer options for auto-creating primary key values, such as AUTOINCREMENT, SERIAL, etc. SQLAlchemy will use these default methods for creating primary key values if no Sequence is present on the table metadata.</p> + +<p>A sequence can also be specified with <span class="codeline">optional=True</span> which indicates the Sequence should only be used on a database that requires an explicit sequence, and not those that supply some other method of providing integer values. At the moment, it essentially means "use this sequence only with Oracle and not Postgres".</p> + +<p>More docs TODO in this area include the ColumnDefault and PassiveDefault objects which provide more options to automatic generation of column values.</p> </ins><span class="cx"> </&> </span><span class="cx"> </span><span class="cx"> </&> </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-03-03 14:46:49
|
<!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>[1085] sqlalchemy/trunk/lib/sqlalchemy/ext/activemapper.py: rudimentary support for many-to-many relation.</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1085</dd> <dt>Author</dt> <dd>jeff</dd> <dt>Date</dt> <dd>2006-03-03 08:46:39 -0600 (Fri, 03 Mar 2006)</dd> </dl> <h3>Log Message</h3> <pre>rudimentary support for many-to-many relation. Still requires a separately defined intermediate table.</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunklibsqlalchemyextactivemapperpy">sqlalchemy/trunk/lib/sqlalchemy/ext/activemapper.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunklibsqlalchemyextactivemapperpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/ext/activemapper.py (1084 => 1085)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/ext/activemapper.py 2006-03-03 00:24:41 UTC (rev 1084) +++ sqlalchemy/trunk/lib/sqlalchemy/ext/activemapper.py 2006-03-03 14:46:39 UTC (rev 1085) </span><span class="lines">@@ -25,8 +25,8 @@ </span><span class="cx"> self.colname = colname </span><span class="cx"> self.foreign_key = foreign_key </span><span class="cx"> self.primary_key = primary_key </span><del>- self.unique = kwargs.pop( 'unique', False ) - self.indexed = kwargs.pop( 'indexed', self.unique ) </del><ins>+# self.unique = kwargs.pop( 'unique', None ) +# self.index = kwargs.pop( 'indexed', None ) </ins><span class="cx"> self.kwargs = kwargs </span><span class="cx"> self.args = args </span><span class="cx"> </span><span class="lines">@@ -34,15 +34,16 @@ </span><span class="cx"> # declarative relationship declaration </span><span class="cx"> # </span><span class="cx"> class relationship(object): </span><del>- def __init__(self, classname, colname=None, backref=None, private=False, lazy=True, uselist=True): </del><ins>+ def __init__(self, classname, colname=None, backref=None, private=False, + lazy=True, uselist=True, secondary=None): </ins><span class="cx"> self.classname = classname </span><span class="cx"> self.colname = colname </span><span class="cx"> self.backref = backref </span><span class="cx"> self.private = private </span><span class="cx"> self.lazy = lazy </span><span class="cx"> self.uselist = uselist </span><ins>+ self.secondary = secondary </ins><span class="cx"> </span><del>- </del><span class="cx"> class one_to_many(relationship): </span><span class="cx"> def __init__(self, classname, colname=None, backref=None, private=False, lazy=True): </span><span class="cx"> relationship.__init__(self, classname, colname, backref, private, lazy, uselist=True) </span><span class="lines">@@ -52,6 +53,10 @@ </span><span class="cx"> def __init__(self, classname, colname=None, backref=None, private=False, lazy=True): </span><span class="cx"> relationship.__init__(self, classname, colname, backref, private, lazy, uselist=False) </span><span class="cx"> </span><ins>+class many_to_many(relationship): + def __init__(self, classname, secondary, backref=None, lazy=True): + relationship.__init__(self, classname, None, backref, False, lazy, + uselist=True, secondary=secondary) </ins><span class="cx"> </span><span class="cx"> </span><span class="cx"> # </span><span class="lines">@@ -73,7 +78,8 @@ </span><span class="cx"> relations = {} </span><span class="cx"> for propname, reldesc in klass.relations.items(): </span><span class="cx"> relclass = ActiveMapperMeta.classes[reldesc.classname] </span><del>- relations[propname] = relation(relclass, </del><ins>+ relations[propname] = relation(relclass.mapper, + secondary=reldesc.secondary, </ins><span class="cx"> backref=reldesc.backref, </span><span class="cx"> private=reldesc.private, </span><span class="cx"> lazy=reldesc.lazy, </span><span class="lines">@@ -122,10 +128,10 @@ </span><span class="cx"> primary_key=value.primary_key, </span><span class="cx"> *value.args, **value.kwargs) </span><span class="cx"> columns.append(col) </span><del>- if value.indexed: - # create a Index object for the column - index= Index( "%s_idx" % (value.colname or name), - col, unique= value.unique ) </del><ins>+# if value.indexed: +# # create a Index object for the column +# index= Index( "%s_idx" % (value.colname or name), +# col, unique= value.unique ) </ins><span class="cx"> continue </span><span class="cx"> </span><span class="cx"> if isinstance(value, relationship): </span><span class="lines">@@ -155,4 +161,5 @@ </span><span class="cx"> </span><span class="cx"> def create_tables(): </span><span class="cx"> for klass in ActiveMapperMeta.classes.values(): </span><del>- klass.table.create() </del><span class="cx">\ No newline at end of file </span><ins>+ klass.table.create() + </ins></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-03-03 00:24: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>[1084] sqlalchemy/trunk/test: added util.Logger object with configurable thread/timestamp view</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1084</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-03-02 18:24:41 -0600 (Thu, 02 Mar 2006)</dd> </dl> <h3>Log Message</h3> <pre>added util.Logger object with configurable thread/timestamp view</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunklibsqlalchemyenginepy">sqlalchemy/trunk/lib/sqlalchemy/engine.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemypoolpy">sqlalchemy/trunk/lib/sqlalchemy/pool.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemyutilpy">sqlalchemy/trunk/lib/sqlalchemy/util.py</a></li> <li><a href="#sqlalchemytrunktestenginespy">sqlalchemy/trunk/test/engines.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 (1083 => 1084)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/engine.py 2006-03-02 17:38:37 UTC (rev 1083) +++ sqlalchemy/trunk/lib/sqlalchemy/engine.py 2006-03-03 00:24:41 UTC (rev 1084) </span><span class="lines">@@ -186,10 +186,7 @@ </span><span class="cx"> self.context = util.ThreadLocal(raiseerror=False) </span><span class="cx"> self._ischema = None </span><span class="cx"> self._figure_paramstyle() </span><del>- if logger is None: - self.logger = sys.stdout - else: - self.logger = logger </del><ins>+ self.logger = logger or util.Logger(origin='engine') </ins><span class="cx"> </span><span class="cx"> def _get_ischema(self): </span><span class="cx"> # We use a property for ischema so that the accessor </span><span class="lines">@@ -607,7 +604,7 @@ </span><span class="cx"> </span><span class="cx"> def log(self, msg): </span><span class="cx"> """logs a message using this SQLEngine's logger stream.""" </span><del>- self.logger.write(msg + "\n") </del><ins>+ self.logger.write(msg) </ins><span class="cx"> </span><span class="cx"> </span><span class="cx"> class ResultProxy: </span><span class="lines">@@ -685,7 +682,7 @@ </span><span class="cx"> """fetches one row, just like DBAPI cursor.fetchone().""" </span><span class="cx"> row = self.cursor.fetchone() </span><span class="cx"> if row is not None: </span><del>- if self.echo: print repr(row) </del><ins>+ if self.echo: self.engine.log(repr(row)) </ins><span class="cx"> return RowProxy(self, row) </span><span class="cx"> else: </span><span class="cx"> return None </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemypoolpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/pool.py (1083 => 1084)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/pool.py 2006-03-02 17:38:37 UTC (rev 1083) +++ sqlalchemy/trunk/lib/sqlalchemy/pool.py 2006-03-03 00:24:41 UTC (rev 1084) </span><span class="lines">@@ -11,6 +11,7 @@ </span><span class="cx"> simply by calling regular DBAPI connect() methods.""" </span><span class="cx"> </span><span class="cx"> import Queue, weakref, string, cPickle </span><ins>+import util </ins><span class="cx"> </span><span class="cx"> try: </span><span class="cx"> import thread </span><span class="lines">@@ -69,10 +70,11 @@ </span><span class="cx"> </span><span class="cx"> </span><span class="cx"> class Pool(object): </span><del>- def __init__(self, echo = False, use_threadlocal = True): </del><ins>+ def __init__(self, echo = False, use_threadlocal = True, logger=None): </ins><span class="cx"> self._threadconns = weakref.WeakValueDictionary() </span><span class="cx"> self._use_threadlocal = use_threadlocal </span><span class="cx"> self._echo = echo </span><ins>+ self._logger = logger or util.Logger(origin='pool') </ins><span class="cx"> </span><span class="cx"> def connect(self): </span><span class="cx"> if not self._use_threadlocal: </span><span class="lines">@@ -115,7 +117,7 @@ </span><span class="cx"> raise NotImplementedError() </span><span class="cx"> </span><span class="cx"> def log(self, msg): </span><del>- print msg </del><ins>+ self.logger.write(msg) </ins><span class="cx"> </span><span class="cx"> class ConnectionFairy(object): </span><span class="cx"> def __init__(self, pool): </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemyutilpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/util.py (1083 => 1084)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/util.py 2006-03-02 17:38:37 UTC (rev 1083) +++ sqlalchemy/trunk/lib/sqlalchemy/util.py 2006-03-03 00:24:41 UTC (rev 1084) </span><span class="lines">@@ -5,7 +5,7 @@ </span><span class="cx"> # the MIT License: http://www.opensource.org/licenses/mit-license.php </span><span class="cx"> </span><span class="cx"> __all__ = ['OrderedProperties', 'OrderedDict', 'generic_repr', 'HashSet', 'AttrProp'] </span><del>-import thread, weakref, UserList,string, inspect </del><ins>+import thread, threading, weakref, UserList, time, string, inspect, sys </ins><span class="cx"> from exceptions import * </span><span class="cx"> </span><span class="cx"> def to_list(x): </span><span class="lines">@@ -51,7 +51,34 @@ </span><span class="cx"> return obj.hash_key() </span><span class="cx"> else: </span><span class="cx"> return repr(obj) </span><del>- </del><ins>+ +class Logger(object): + """defines various forms of logging""" + def __init__(self, logger=None, usethreads=False, usetimestamp=True, origin=None): + self.logger = logger or sys.stdout + self.usethreads = usethreads + self.usetimestamp = usetimestamp + self.origin = origin + def write(self, msg): + if self.usetimestamp: + t = time.time() + ms = (t - long(t)) * 1000 + timestamp = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(t)) + timestamp = "[%s,%03d]" % (timestamp, ms) + else: + timestamp = None + if self.origin: + origin = "[%s]" % self.origin + origin = "%-8s" % origin + else: + origin = None + if self.usethreads: + threadname = threading.currentThread().getName() + threadname = "[" + threadname + ' '*(8-len(threadname)) + "]" + else: + threadname = None + self.logger.write(string.join([s for s in (timestamp, threadname, origin) if s is not None]) + ": " + msg + "\n") + </ins><span class="cx"> class OrderedProperties(object): </span><span class="cx"> """ </span><span class="cx"> An object that maintains the order in which attributes are set upon it. </span></span></pre></div> <a id="sqlalchemytrunktestenginespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/test/engines.py (1083 => 1084)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/test/engines.py 2006-03-02 17:38:37 UTC (rev 1083) +++ sqlalchemy/trunk/test/engines.py 2006-03-03 00:24:41 UTC (rev 1084) </span><span class="lines">@@ -121,7 +121,7 @@ </span><span class="cx"> table.insert().execute({'multi_id':3,'multi_rev':3,'name':'row3', 'value':'value3'}) </span><span class="cx"> table.select().execute().fetchall() </span><span class="cx"> table.drop() </span><del>- </del><ins>+ </ins><span class="cx"> def testtoengine(self): </span><span class="cx"> db = ansisql.engine() </span><span class="cx"> </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-03-02 17:38:55
|
<!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>[1083] sqlalchemy/trunk/lib/sqlalchemy/databases/mysql.py: changed ENGINE to TYPE, for mysql 4 compatibility</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1083</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-03-02 11:38:37 -0600 (Thu, 02 Mar 2006)</dd> </dl> <h3>Log Message</h3> <pre>changed ENGINE to TYPE, for mysql 4 compatibility</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunklibsqlalchemydatabasesmysqlpy">sqlalchemy/trunk/lib/sqlalchemy/databases/mysql.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunklibsqlalchemydatabasesmysqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/databases/mysql.py (1082 => 1083)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/databases/mysql.py 2006-03-02 02:11:51 UTC (rev 1082) +++ sqlalchemy/trunk/lib/sqlalchemy/databases/mysql.py 2006-03-02 17:38:37 UTC (rev 1083) </span><span class="lines">@@ -270,7 +270,7 @@ </span><span class="cx"> def post_create_table(self, table): </span><span class="cx"> mysql_engine = table.kwargs.get('mysql_engine', None) </span><span class="cx"> if mysql_engine is not None: </span><del>- return " ENGINE=%s" % mysql_engine </del><ins>+ return " TYPE=%s" % mysql_engine </ins><span class="cx"> else: </span><span class="cx"> return "" </span><span class="cx"> </span></span></pre> </div> </div> </body> </html> |