sqlalchemy-commits Mailing List for SQLAlchemy (Page 358)
Brought to you by:
zzzeek
You can subscribe to this list here.
2006 |
Jan
|
Feb
(74) |
Mar
(167) |
Apr
(127) |
May
(190) |
Jun
(119) |
Jul
(77) |
Aug
(82) |
Sep
(84) |
Oct
(153) |
Nov
(45) |
Dec
(54) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2007 |
Jan
(109) |
Feb
(80) |
Mar
(110) |
Apr
(106) |
May
(92) |
Jun
(147) |
Jul
(288) |
Aug
(307) |
Sep
(108) |
Oct
(156) |
Nov
(147) |
Dec
(134) |
2008 |
Jan
(126) |
Feb
(91) |
Mar
(184) |
Apr
(208) |
May
(212) |
Jun
(54) |
Jul
(106) |
Aug
(80) |
Sep
(58) |
Oct
(80) |
Nov
(119) |
Dec
(220) |
2009 |
Jan
(202) |
Feb
(50) |
Mar
(70) |
Apr
(46) |
May
(80) |
Jun
(61) |
Jul
(146) |
Aug
(81) |
Sep
(71) |
Oct
(74) |
Nov
(66) |
Dec
(82) |
2010 |
Jan
(112) |
Feb
(169) |
Mar
(235) |
Apr
(77) |
May
(22) |
Jun
(31) |
Jul
(46) |
Aug
(46) |
Sep
(70) |
Oct
(36) |
Nov
(37) |
Dec
(79) |
2011 |
Jan
(46) |
Feb
(54) |
Mar
(65) |
Apr
(73) |
May
(31) |
Jun
(46) |
Jul
(40) |
Aug
(36) |
Sep
(44) |
Oct
(33) |
Nov
(19) |
Dec
(10) |
2012 |
Jan
(60) |
Feb
(37) |
Mar
(35) |
Apr
(28) |
May
(27) |
Jun
(50) |
Jul
(33) |
Aug
(88) |
Sep
(64) |
Oct
(74) |
Nov
(62) |
Dec
(41) |
2013 |
Jan
(30) |
Feb
(37) |
Mar
(39) |
Apr
(52) |
May
(40) |
Jun
(85) |
Jul
(74) |
Aug
(76) |
Sep
(26) |
Oct
(76) |
Nov
(63) |
Dec
(65) |
2014 |
Jan
(68) |
Feb
(82) |
Mar
(87) |
Apr
(24) |
May
(66) |
Jun
(34) |
Jul
(86) |
Aug
(75) |
Sep
(70) |
Oct
(41) |
Nov
(23) |
Dec
(53) |
2015 |
Jan
(40) |
Feb
(39) |
Mar
(69) |
Apr
(64) |
May
(40) |
Jun
(43) |
Jul
(20) |
Aug
(48) |
Sep
(38) |
Oct
(28) |
Nov
(34) |
Dec
(44) |
2016 |
Jan
(82) |
Feb
(49) |
Mar
(25) |
Apr
(21) |
May
(19) |
Jun
(46) |
Jul
(38) |
Aug
(21) |
Sep
(33) |
Oct
(44) |
Nov
(26) |
Dec
(10) |
2017 |
Jan
(52) |
Feb
(18) |
Mar
(61) |
Apr
(43) |
May
(57) |
Jun
(36) |
Jul
(37) |
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: <co...@sq...> - 2006-05-25 21:14: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>[1513] sqlalchemy/branches/schema/lib/sqlalchemy/databases/mssql.py: 0.2 update</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1513</dd> <dt>Author</dt> <dd>ram</dd> <dt>Date</dt> <dd>2006-05-25 16:14:00 -0500 (Thu, 25 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>0.2 update</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemalibsqlalchemydatabasesmssqlpy">sqlalchemy/branches/schema/lib/sqlalchemy/databases/mssql.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschemalibsqlalchemydatabasesmssqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/databases/mssql.py (1512 => 1513)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/databases/mssql.py 2006-05-25 18:30:36 UTC (rev 1512) +++ sqlalchemy/branches/schema/lib/sqlalchemy/databases/mssql.py 2006-05-25 21:14:00 UTC (rev 1513) </span><span class="lines">@@ -38,10 +38,11 @@ </span><span class="cx"> </span><span class="cx"> import sqlalchemy.sql as sql </span><span class="cx"> import sqlalchemy.engine as engine </span><ins>+import sqlalchemy.engine.default as default </ins><span class="cx"> import sqlalchemy.schema as schema </span><span class="cx"> import sqlalchemy.ansisql as ansisql </span><span class="cx"> import sqlalchemy.types as sqltypes </span><del>-from sqlalchemy import * </del><ins>+import sqlalchemy.exceptions as exceptions </ins><span class="cx"> </span><span class="cx"> try: </span><span class="cx"> import adodbapi as dbmodule </span><span class="lines">@@ -65,10 +66,10 @@ </span><span class="cx"> make_connect_string = lambda keys: [[],{}] </span><span class="cx"> </span><span class="cx"> class MSNumeric(sqltypes.Numeric): </span><del>- def convert_result_value(self, value, engine): </del><ins>+ def convert_result_value(self, value, dialect): </ins><span class="cx"> return value </span><span class="cx"> </span><del>- def convert_bind_param(self, value, engine): </del><ins>+ def convert_bind_param(self, value, dialect): </ins><span class="cx"> if value is None: </span><span class="cx"> # Not sure that this exception is needed </span><span class="cx"> return value </span><span class="lines">@@ -81,7 +82,7 @@ </span><span class="cx"> class MSFloat(sqltypes.Float): </span><span class="cx"> def get_col_spec(self): </span><span class="cx"> return "FLOAT(%(precision)s)" % {'precision': self.precision} </span><del>- def convert_bind_param(self, value, engine): </del><ins>+ def convert_bind_param(self, value, dialect): </ins><span class="cx"> """By converting to string, we can use Decimal types round-trip.""" </span><span class="cx"> return str(value) </span><span class="cx"> </span><span class="lines">@@ -97,13 +98,14 @@ </span><span class="cx"> def get_col_spec(self): </span><span class="cx"> return "DATETIME" </span><span class="cx"> </span><del>- def convert_bind_param(self, value, engine): </del><ins>+ def convert_bind_param(self, value, dialect): </ins><span class="cx"> if hasattr(value, "isoformat"): </span><del>- return value.isoformat(' ') </del><ins>+ #return value.isoformat(' ') + return value.strftime('%Y-%m-%d %H:%M:%S') # isoformat() bings on apodbapi -- reported/suggested by Peter Buschman </ins><span class="cx"> else: </span><span class="cx"> return value </span><span class="cx"> </span><del>- def convert_result_value(self, value, engine): </del><ins>+ def convert_result_value(self, value, dialect): </ins><span class="cx"> # adodbapi will return datetimes with empty time values as datetime.date() objects. Promote them back to full datetime.datetime() </span><span class="cx"> if value and not hasattr(value, 'second'): </span><span class="cx"> return datetime.datetime(value.year, value.month, value.day) </span><span class="lines">@@ -113,12 +115,12 @@ </span><span class="cx"> def get_col_spec(self): </span><span class="cx"> return "SMALLDATETIME" </span><span class="cx"> </span><del>- def convert_bind_param(self, value, engine): </del><ins>+ def convert_bind_param(self, value, dialect): </ins><span class="cx"> if value and hasattr(value, "isoformat"): </span><span class="cx"> return value.isoformat() </span><span class="cx"> return value </span><span class="cx"> </span><del>- def convert_result_value(self, value, engine): </del><ins>+ def convert_result_value(self, value, dialect): </ins><span class="cx"> # pymssql will return SMALLDATETIME values as datetime.datetime(), truncate it back to datetime.date() </span><span class="cx"> if value and hasattr(value, 'second'): </span><span class="cx"> return value.date() </span><span class="lines">@@ -184,16 +186,49 @@ </span><span class="cx"> ('host',"Hostname", None), </span><span class="cx"> ]} </span><span class="cx"> </span><del>-class MSSQLEngine(ansisql.ANSISQLEngine): - def __init__(self, opts, module = None, **params): - if module is None: - self.module = dbmodule - self.opts = opts or {} - ansisql.ANSISQLEngine.__init__(self, **params) </del><ins>+class MSSQLExecutionContext(default.DefaultExecutionContext): + def pre_exec(self, engine, proxy, compiled, parameters, **kwargs): + """ MS-SQL has a special mode for inserting non-NULL values into IDENTITY columns. Activate it if needed. """ + if getattr(compiled, "isinsert", False): + self.IINSERT = False + self.HASIDENT = False + for c in compiled.statement.table.c: + if hasattr(c,'sequence'): + self.HASIDENT = True + if parameters.has_key(c.name): + self.IINSERT = True + break + if self.IINSERT: + proxy("SET IDENTITY_INSERT %s ON" % compiled.statement.table.name) </ins><span class="cx"> </span><ins>+ def post_exec(self, engine, proxy, compiled, parameters, **kwargs): + """ Turn off the INDENTITY_INSERT mode if it's been activated, and fetch recently inserted IDENTIFY values (works only for one column) """ + if getattr(compiled, "isinsert", False): + if self.IINSERT: + proxy("SET IDENTITY_INSERT %s OFF" % compiled.statement.table.name) + self.IINSERT = False + elif self.HASIDENT: + cursor = proxy("SELECT @@IDENTITY AS lastrowid") + row = cursor.fetchone() + self.last_inserted_ids = [row[0]] + self.HASIDENT = False + +class MSSQLDialect(ansisql.ANSIDialect): + def __init__(self, module = None, **params): + self.module = module or dbmodule + self.opts = {} + ansisql.ANSIDialect.__init__(self, **params) + + def create_connect_args(self, url): + self.opts = url.translate_connect_args(['host', 'database', 'user', 'password', 'port']) + return ([], self.opts) + </ins><span class="cx"> def connect_args(self): </span><span class="cx"> return make_connect_string(self.opts) </span><span class="cx"> </span><ins>+ def create_execution_context(self): + return MSSQLExecutionContext(self) + </ins><span class="cx"> def type_descriptor(self, typeobj): </span><span class="cx"> return sqltypes.adapt_type(typeobj, colspecs) </span><span class="cx"> </span><span class="lines">@@ -204,14 +239,17 @@ </span><span class="cx"> return True </span><span class="cx"> </span><span class="cx"> def compiler(self, statement, bindparams, **kwargs): </span><del>- return MSSQLCompiler(statement, bindparams, engine=self, **kwargs) </del><ins>+ return MSSQLCompiler(self, statement, bindparams, **kwargs) </ins><span class="cx"> </span><del>- def schemagenerator(self, **params): - return MSSQLSchemaGenerator(self, **params) </del><ins>+ def schemagenerator(self, *args, **kwargs): + return MSSQLSchemaGenerator(*args, **kwargs) </ins><span class="cx"> </span><del>- def schemadropper(self, **params): - return MSSQLSchemaDropper(self, **params) </del><ins>+ def schemadropper(self, *args, **kwargs): + return MSSQLSchemaDropper(*args, **kwargs) </ins><span class="cx"> </span><ins>+ def defaultrunner(self, engine, proxy): + return MSSQLDefaultRunner(engine, proxy) + </ins><span class="cx"> def get_default_schema_name(self): </span><span class="cx"> return "dbo" </span><span class="cx"> </span><span class="lines">@@ -229,10 +267,10 @@ </span><span class="cx"> self.context.rowcount = c.rowcount </span><span class="cx"> c.DBPROP_COMMITPRESERVE = "Y" </span><span class="cx"> except Exception, e: </span><del>- # del c.parent # Close the Parent Connection, delete it from the pool </del><ins>+ # del c.parent # Close the Parent Connection, delete it from the pool columns = ischema.columns.toengine(self) + </ins><span class="cx"> raise exceptions.SQLError(statement, parameters, e) </span><span class="cx"> </span><del>- </del><span class="cx"> def do_rollback(self, connection): </span><span class="cx"> """implementations might want to put logic here for turning autocommit on/off, etc.""" </span><span class="cx"> if do_commit: </span><span class="lines">@@ -288,36 +326,11 @@ </span><span class="cx"> c.supportsTransactions = 0 </span><span class="cx"> return c </span><span class="cx"> </span><del>- def pre_exec(self, proxy, compiled, parameters, **kwargs): - """ MS-SQL has a special mode for inserting non-NULL values into IDENTITY columns. Activate it if needed. """ - if getattr(compiled, "isinsert", False): - self.context.IINSERT = False - self.context.HASIDENT = False - for c in compiled.statement.table.c: - if hasattr(c,'sequence'): - self.context.HASIDENT = True - if parameters.has_key(c.name): - self.context.IINSERT = True - break - if self.context.IINSERT: - proxy("SET IDENTITY_INSERT %s ON" % compiled.statement.table.name) - - def post_exec(self, proxy, compiled, parameters, **kwargs): - """ Turn off the INDENTITY_INSERT mode if it's been activated, and fetch recently inserted IDENTIFY values (works only for one column) """ - if getattr(compiled, "isinsert", False): - if self.context.IINSERT: - proxy("SET IDENTITY_INSERT %s OFF" % compiled.statement.table.name) - self.context.IINSERT = False - elif self.context.HASIDENT: - cursor = proxy("SELECT @@IDENTITY AS lastrowid") - row = cursor.fetchone() - self.context.last_inserted_ids = [row[0]] - self.context.HASIDENT = False - </del><ins>+ </ins><span class="cx"> def dbapi(self): </span><span class="cx"> return self.module </span><span class="cx"> </span><del>- def reflecttable(self, table): </del><ins>+ def reflecttable(self, connection, table): </ins><span class="cx"> import sqlalchemy.databases.information_schema as ischema </span><span class="cx"> </span><span class="cx"> # Get base columns </span><span class="lines">@@ -326,12 +339,12 @@ </span><span class="cx"> else: </span><span class="cx"> current_schema = self.get_default_schema_name() </span><span class="cx"> </span><del>- columns = ischema.gen_columns.toengine(self) </del><ins>+ columns = ischema.columns.toengine(self) </ins><span class="cx"> s = select([columns], </span><span class="cx"> current_schema and sql.and_(columns.c.table_name==table.name, columns.c.table_schema==current_schema) or columns.c.table_name==table.name, </span><span class="cx"> order_by=[columns.c.ordinal_position]) </span><span class="cx"> </span><del>- c = s.execute() </del><ins>+ c = connection.execute(s) </ins><span class="cx"> while True: </span><span class="cx"> row = c.fetchone() </span><span class="cx"> if row is None: </span><span class="lines">@@ -352,7 +365,6 @@ </span><span class="cx"> if a is not None: </span><span class="cx"> args.append(a) </span><span class="cx"> coltype = ischema_names[type] </span><del>- </del><span class="cx"> coltype = coltype(*args) </span><span class="cx"> colargs= [] </span><span class="cx"> if default is not None: </span><span class="lines">@@ -363,7 +375,9 @@ </span><span class="cx"> </span><span class="cx"> # We also run an sp_columns to check for identity columns: </span><span class="cx"> # FIXME: note that this only fetches the existence of an identity column, not it's properties like (seed, increment) </span><del>- cursor = table.engine.execute("sp_columns " + table.name, {}) </del><ins>+ # also, add a check to make sure we specify the schema name of the table + # cursor = table.engine.execute("sp_columns " + table.name, {}) + cursor = connection.execute("sp_columns " + table.name) </ins><span class="cx"> while True: </span><span class="cx"> row = cursor.fetchone() </span><span class="cx"> if row is None: </span><span class="lines">@@ -375,10 +389,10 @@ </span><span class="cx"> ic.sequence = schema.Sequence(ic.name + '_identity') </span><span class="cx"> </span><span class="cx"> # Add constraints </span><del>- RR = ischema.gen_ref_constraints.toengine(self) #information_schema.referential_constraints - TC = ischema.gen_constraints.toengine(self) #information_schema.table_constraints - C = ischema.gen_column_constraints.toengine(self).alias('C') #information_schema.constraint_column_usage: the constrained column - R = ischema.gen_column_constraints.toengine(self).alias('R') #information_schema.constraint_column_usage: the referenced column </del><ins>+ RR = ischema.ref_constraints.toengine(self) #information_schema.referential_constraints + TC = ischema.constraints.toengine(self) #information_schema.table_constraints + C = ischema.column_constraints.toengine(self).alias('C') #information_schema.constraint_column_usage: the constrained column + R = ischema.column_constraints.toengine(self).alias('R') #information_schema.constraint_column_usage: the referenced column </ins><span class="cx"> </span><span class="cx"> fromjoin = TC.join(RR, RR.c.constraint_name == TC.c.constraint_name).join(C, C.c.constraint_name == RR.c.constraint_name) </span><span class="cx"> fromjoin = fromjoin.join(R, R.c.constraint_name == RR.c.unique_constraint_name) </span><span class="lines">@@ -389,7 +403,7 @@ </span><span class="cx"> from_obj = [fromjoin] </span><span class="cx"> ) </span><span class="cx"> </span><del>- c = s.execute() </del><ins>+ c = connection.execute(s) </ins><span class="cx"> </span><span class="cx"> while True: </span><span class="cx"> row = c.fetchone() </span><span class="lines">@@ -412,8 +426,8 @@ </span><span class="cx"> </span><span class="cx"> </span><span class="cx"> class MSSQLCompiler(ansisql.ANSICompiler): </span><del>- def __init__(self, *args, **kwargs): - super(MSSQLCompiler, self).__init__(*args, **kwargs) </del><ins>+ def __init__(self, dialect, statement, parameters, **kwargs): + super(MSSQLCompiler, self).__init__(dialect, statement, parameters, **kwargs) </ins><span class="cx"> self.tablealiases = {} </span><span class="cx"> </span><span class="cx"> def visit_select_precolumns(self, select): </span><span class="lines">@@ -463,7 +477,7 @@ </span><span class="cx"> colspec = column.name + " " + column.type.engine_impl(self.engine).get_col_spec() </span><span class="cx"> </span><span class="cx"> # install a IDENTITY Sequence if we have an implicit IDENTITY column </span><del>- if column.primary_key and isinstance(column.type, types.Integer): </del><ins>+ if column.primary_key and isinstance(column.type, sqltypes.Integer): </ins><span class="cx"> if column.default is None or (isinstance(column.default, schema.Sequence) and column.default.optional): </span><span class="cx"> column.sequence = schema.Sequence(column.name + '_seq') </span><span class="cx"> </span><span class="lines">@@ -490,3 +504,8 @@ </span><span class="cx"> def visit_index(self, index): </span><span class="cx"> self.append("\nDROP INDEX " + index.table.name + "." + index.name) </span><span class="cx"> self.execute() </span><ins>+ +class MSSQLDefaultRunner(ansisql.ANSIDefaultRunner): + pass + +dialect = MSSQLDialect </ins></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-05-25 18:30: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>[1512] sqlalchemy/trunk/lib/sqlalchemy/orm/unitofwork.py: some TODOs</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1512</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-05-25 13:30:36 -0500 (Thu, 25 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>some TODOs</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunklibsqlalchemyormunitofworkpy">sqlalchemy/trunk/lib/sqlalchemy/orm/unitofwork.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunklibsqlalchemyormunitofworkpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/orm/unitofwork.py (1511 => 1512)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/orm/unitofwork.py 2006-05-25 18:20:39 UTC (rev 1511) +++ sqlalchemy/trunk/lib/sqlalchemy/orm/unitofwork.py 2006-05-25 18:30:36 UTC (rev 1512) </span><span class="lines">@@ -607,10 +607,18 @@ </span><span class="cx"> def execute(self, trans): </span><span class="cx"> """executes this UOWTask. saves objects to be saved, processes all dependencies </span><span class="cx"> that have been registered, and deletes objects to be deleted. """ </span><ins>+ + # a "circular" task is a circularly-sorted collection of UOWTask/UOWTaskElements + # derived from the components of this UOWTask, which accounts for inter-row dependencies. + # if one was created for this UOWTask, it replaces the execution for this UOWTask. </ins><span class="cx"> if self.circular is not None: </span><span class="cx"> self.circular.execute(trans) </span><span class="cx"> return </span><span class="cx"> </span><ins>+ # TODO: apply the same recursive inheritance logic to the cyclical tasks/dependencies + # TODO: add a visitation system to the UOW classes and have this execution called + # from a separate executor object ? (would also handle dumping) + </ins><span class="cx"> self._save_objects(trans) </span><span class="cx"> for dep in self.cyclical_dependencies: </span><span class="cx"> dep.execute(trans, False) </span><span class="lines">@@ -784,7 +792,7 @@ </span><span class="cx"> return buf.getvalue() </span><span class="cx"> </span><span class="cx"> def _dump(self, buf, indent=0, circularparent=None): </span><del>- </del><ins>+ # TODO: the dumper should go into a separate module/class, allow different dumper implementations </ins><span class="cx"> def _indent(): </span><span class="cx"> return " | " * indent </span><span class="cx"> </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-05-25 18:20: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>[1511] sqlalchemy/trunk/lib/sqlalchemy/orm/query.py: bind parameter conflict in _get() resolved</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1511</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-05-25 13:20:39 -0500 (Thu, 25 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>bind parameter conflict in _get() resolved</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunklibsqlalchemyormquerypy">sqlalchemy/trunk/lib/sqlalchemy/orm/query.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunklibsqlalchemyormquerypy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/orm/query.py (1510 => 1511)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/orm/query.py 2006-05-25 17:53:06 UTC (rev 1510) +++ sqlalchemy/trunk/lib/sqlalchemy/orm/query.py 2006-05-25 18:20:39 UTC (rev 1511) </span><span class="lines">@@ -24,7 +24,7 @@ </span><span class="cx"> if not hasattr(mapper, '_get_clause'): </span><span class="cx"> _get_clause = sql.and_() </span><span class="cx"> for primary_key in self.mapper.pks_by_table[self.table]: </span><del>- _get_clause.clauses.append(primary_key == sql.bindparam("pk_"+primary_key.key)) </del><ins>+ _get_clause.clauses.append(primary_key == sql.bindparam("pk_"+primary_key._label)) </ins><span class="cx"> self.mapper._get_clause = _get_clause </span><span class="cx"> self._get_clause = self.mapper._get_clause </span><span class="cx"> def _get_session(self): </span><span class="lines">@@ -266,7 +266,7 @@ </span><span class="cx"> i = 0 </span><span class="cx"> params = {} </span><span class="cx"> for primary_key in self.mapper.pks_by_table[self.table]: </span><del>- params["pk_"+primary_key.key] = ident[i] </del><ins>+ params["pk_"+primary_key._label] = ident[i] </ins><span class="cx"> # if there are not enough elements in the given identifier, then </span><span class="cx"> # use the previous identifier repeatedly. this is a workaround for the issue </span><span class="cx"> # in [ticket:185], where a mapper that uses joined table inheritance needs to specify </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-05-25 17:53:18
|
<!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>[1510] sqlalchemy/trunk/lib/sqlalchemy/orm: pretty major change to inheritance topological sorting - mapper dependencies are calculated</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1510</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-05-25 12:53:06 -0500 (Thu, 25 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>pretty major change to inheritance topological sorting - mapper dependencies are calculated based on their ultimate "base inherited" mapper, UOWTasks organized into recursive inheritance structures based on the inheritance of the mappers. this allows tasks across a class/mapper inheritance hierarchy to properly interact with other dependency processors and sub-tasks.</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunklibsqlalchemyormdependencypy">sqlalchemy/trunk/lib/sqlalchemy/orm/dependency.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemyormmapperpy">sqlalchemy/trunk/lib/sqlalchemy/orm/mapper.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemyormunitofworkpy">sqlalchemy/trunk/lib/sqlalchemy/orm/unitofwork.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunklibsqlalchemyormdependencypy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/orm/dependency.py (1509 => 1510)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/orm/dependency.py 2006-05-25 16:23:39 UTC (rev 1509) +++ sqlalchemy/trunk/lib/sqlalchemy/orm/dependency.py 2006-05-25 17:53:06 UTC (rev 1510) </span><span class="lines">@@ -203,7 +203,7 @@ </span><span class="cx"> uowcommit.register_object(obj, postupdate=True) </span><span class="cx"> </span><span class="cx"> def preprocess_dependencies(self, task, deplist, uowcommit, delete = False): </span><del>- #print self.mapper.table.name + " " + self.key + " " + repr(len(deplist)) + " process_dep isdelete " + repr(delete) + " direction " + repr(self.direction) </del><ins>+ #print self.mapper.mapped_table.name + " " + self.key + " " + repr(len(deplist)) + " PRE process_dep isdelete " + repr(delete) + " direction " + repr(self.direction) </ins><span class="cx"> # TODO: post_update instructions should be established in this step as well </span><span class="cx"> # (and executed in the regular traversal) </span><span class="cx"> if self.post_update: </span><span class="lines">@@ -359,6 +359,7 @@ </span><span class="cx"> for the many-to-many update task.""" </span><span class="cx"> def __init__(self, mapper): </span><span class="cx"> self.mapper = mapper </span><ins>+ self._inheriting_mappers = [] </ins><span class="cx"> def register_dependencies(self, uowcommit): </span><span class="cx"> pass </span><span class="cx"> def save_obj(self, *args, **kwargs): </span><span class="lines">@@ -367,3 +368,5 @@ </span><span class="cx"> pass </span><span class="cx"> def _primary_mapper(self): </span><span class="cx"> return self </span><ins>+ def base_mapper(self): + return self </ins><span class="cx">\ No newline at end of file </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemyormmapperpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/orm/mapper.py (1509 => 1510)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/orm/mapper.py 2006-05-25 16:23:39 UTC (rev 1509) +++ sqlalchemy/trunk/lib/sqlalchemy/orm/mapper.py 2006-05-25 17:53:06 UTC (rev 1510) </span><span class="lines">@@ -282,6 +282,13 @@ </span><span class="cx"> elif (isinstance(column, list) and sql.is_column(column[0])): </span><span class="cx"> props[key] = [self.select_table.corresponding_column(c) for c in prop] </span><span class="cx"> self.__surrogate_mapper = Mapper(self.class_, self.select_table, non_primary=True, properties=props, polymorphic_map=self.polymorphic_map, polymorphic_on=self.polymorphic_on) </span><ins>+ + def base_mapper(self): + """returns the ultimate base mapper in an inheritance chain""" + if self.inherits is not None: + return self.inherits.base_mapper() + else: + return self </ins><span class="cx"> </span><span class="cx"> def add_polymorphic_mapping(self, key, class_or_mapper, entity_name=None): </span><span class="cx"> if isinstance(class_or_mapper, type): </span><span class="lines">@@ -640,7 +647,6 @@ </span><span class="cx"> if primary_key is not None: </span><span class="cx"> i = 0 </span><span class="cx"> for col in self.pks_by_table[table]: </span><del>- #print "col: " + table.name + "." + col.key + " val: " + repr(self._getattrbycolumn(obj, col)) </del><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><span class="lines">@@ -722,8 +728,6 @@ </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><span class="cx"> prop.register_dependencies(uowcommit, *args, **kwargs) </span><del>- if self.inherits is not None: - uowcommit.register_dependency(self.inherits, self) </del><span class="cx"> </span><span class="cx"> def cascade_iterator(self, type, object, recursive=None): </span><span class="cx"> if recursive is None: </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemyormunitofworkpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/orm/unitofwork.py (1509 => 1510)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/orm/unitofwork.py 2006-05-25 16:23:39 UTC (rev 1509) +++ sqlalchemy/trunk/lib/sqlalchemy/orm/unitofwork.py 2006-05-25 17:53:06 UTC (rev 1510) </span><span class="lines">@@ -333,7 +333,10 @@ </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><span class="cx"> # correct for primary mapper (the mapper offcially associated with the class) </span><del>- self.dependencies[(mapper._primary_mapper(), dependency._primary_mapper())] = True </del><ins>+ mapper = mapper._primary_mapper().base_mapper() + dependency = dependency._primary_mapper().base_mapper() + + self.dependencies[(mapper, dependency)] = True </ins><span class="cx"> self._mark_modified() </span><span class="cx"> </span><span class="cx"> def register_processor(self, mapper, processor, mapperfrom): </span><span class="lines">@@ -349,6 +352,7 @@ </span><span class="cx"> # correct for primary mapper (the mapper offcially associated with the class) </span><span class="cx"> mapper = mapper._primary_mapper() </span><span class="cx"> mapperfrom = mapperfrom._primary_mapper() </span><ins>+ </ins><span class="cx"> task = self.get_task_by_mapper(mapper) </span><span class="cx"> targettask = self.get_task_by_mapper(mapperfrom) </span><span class="cx"> up = UOWDependencyProcessor(processor, targettask) </span><span class="lines">@@ -422,7 +426,21 @@ </span><span class="cx"> mappers = util.HashSet() </span><span class="cx"> for task in self.tasks.values(): </span><span class="cx"> mappers.append(task.mapper) </span><del>- </del><ins>+ + def inheriting_tasks(task): + if task.mapper not in mappers: + return + for mapper in task.mapper._inheriting_mappers: + inherit_task = self.tasks.get(mapper, None) + if inherit_task is None: + continue + inheriting_tasks(inherit_task) + task.inheriting_tasks.append(inherit_task) + del mappers[mapper] + + for task in self.tasks.values(): + inheriting_tasks(task) + </ins><span class="cx"> head = DependencySorter(self.dependencies, mappers).sort(allow_all_cycles=True) </span><span class="cx"> #print str(head) </span><span class="cx"> task = sort_hier(head) </span><span class="lines">@@ -525,6 +543,7 @@ </span><span class="cx"> self.cyclical_dependencies = [] </span><span class="cx"> self.circular = None </span><span class="cx"> self.childtasks = [] </span><ins>+ self.inheriting_tasks = [] </ins><span class="cx"> </span><span class="cx"> def is_empty(self): </span><span class="cx"> return len(self.objects) == 0 and len(self.dependencies) == 0 and len(self.childtasks) == 0 </span><span class="lines">@@ -563,7 +582,28 @@ </span><span class="cx"> del self.objects[obj] </span><span class="cx"> except KeyError: </span><span class="cx"> pass </span><del>- </del><ins>+ + def _save_objects(self, trans): + self.mapper.save_obj(self.tosave_objects, trans) + for task in self.inheriting_tasks: + task._save_objects(trans) + def _delete_objects(self, trans): + self.mapper.delete_obj(self.todelete_objects, trans) + for task in self.inheriting_tasks: + task._delete_objects(trans) + def _execute_dependencies(self, trans): + for dep in self.dependencies: + dep.execute(trans, False) + for task in self.inheriting_tasks: + task._execute_dependencies(trans) + for dep in self.dependencies: + dep.execute(trans, True) + def _execute_childtasks(self, trans): + for child in self.childtasks: + child.execute(trans) + for task in self.inheriting_tasks: + task._execute_childtasks(trans) + </ins><span class="cx"> def execute(self, trans): </span><span class="cx"> """executes this UOWTask. saves objects to be saved, processes all dependencies </span><span class="cx"> that have been registered, and deletes objects to be deleted. """ </span><span class="lines">@@ -571,24 +611,20 @@ </span><span class="cx"> self.circular.execute(trans) </span><span class="cx"> return </span><span class="cx"> </span><del>- self.mapper.save_obj(self.tosave_objects, trans) </del><ins>+ self._save_objects(trans) </ins><span class="cx"> for dep in self.cyclical_dependencies: </span><span class="cx"> dep.execute(trans, False) </span><span class="cx"> for element in self.tosave_elements: </span><span class="cx"> for task in element.childtasks: </span><span class="cx"> task.execute(trans) </span><del>- for dep in self.dependencies: - dep.execute(trans, False) - for dep in self.dependencies: - dep.execute(trans, True) </del><ins>+ self._execute_dependencies(trans) </ins><span class="cx"> for dep in self.cyclical_dependencies: </span><span class="cx"> dep.execute(trans, True) </span><del>- for child in self.childtasks: - child.execute(trans) </del><ins>+ self._execute_childtasks(trans) </ins><span class="cx"> for element in self.todelete_elements: </span><span class="cx"> for task in element.childtasks: </span><span class="cx"> task.execute(trans) </span><del>- self.mapper.delete_obj(self.todelete_objects, trans) </del><ins>+ self._delete_objects(trans) </ins><span class="cx"> </span><span class="cx"> tosave_elements = property(lambda self: [rec for rec in self.objects.values() if not rec.isdelete]) </span><span class="cx"> todelete_elements = property(lambda self:[rec for rec in self.objects.values() if rec.isdelete]) </span><span class="lines">@@ -808,6 +844,47 @@ </span><span class="cx"> def _repr(obj): </span><span class="cx"> return "%s(%d)" % (obj.__class__.__name__, id(obj)) </span><span class="cx"> </span><ins>+ def _inheritance_tag(task): + if task is not self: + return (" (inheriting task %s)" % _repr_task(task)) + else: + return "" + + def _dump_saveelements(task): + for rec in task.tosave_elements: + if rec.listonly: + continue + header(buf, _indent() + " |- Save elements"+ _inheritance_tag(task) + "\n") + buf.write(_indent() + " |- " + _repr_task_element(rec) + "\n") + for t in task.inheriting_tasks: + _dump_saveelements(t) + + def _dump_deleteelements(task): + for rec in task.todelete_elements: + if rec.listonly: + continue + header(buf, _indent() + " |- Delete elements"+ _inheritance_tag(task) + "\n") + buf.write(_indent() + " |- " + _repr_task_element(rec) + "\n") + for t in task.inheriting_tasks: + _dump_deleteelements(t) + + def _dump_dependencies(task): + for dep in task.dependencies: + header(buf, _indent() + " |- Save dependencies" + _inheritance_tag(task) + "\n") + _dump_processor(dep, False) + for t in task.inheriting_tasks: + _dump_dependencies(t) + for dep in task.dependencies: + header(buf, _indent() + " |- Delete dependencies" + _inheritance_tag(task) + "\n") + _dump_processor(dep, True) + + def _dump_childtasks(task): + for child in task.childtasks: + header(buf, _indent() + " |- Child tasks" + _inheritance_tag(task) + "\n") + child._dump(buf, indent + 1) + for t in task.inheriting_tasks: + _dump_childtasks(t) + </ins><span class="cx"> if self.circular is not None: </span><span class="cx"> self.circular._dump(buf, indent, self) </span><span class="cx"> return </span><span class="lines">@@ -822,11 +899,7 @@ </span><span class="cx"> buf.write(i + " " + _repr_task(self)) </span><span class="cx"> </span><span class="cx"> buf.write("\n") </span><del>- for rec in self.tosave_elements: - if rec.listonly: - continue - header(buf, _indent() + " |- Save elements\n") - buf.write(_indent() + " |- " + _repr_task_element(rec) + "\n") </del><ins>+ _dump_saveelements(self) </ins><span class="cx"> for dep in self.cyclical_dependencies: </span><span class="cx"> header(buf, _indent() + " |- Cyclical Save dependencies\n") </span><span class="cx"> _dump_processor(dep, False) </span><span class="lines">@@ -834,32 +907,17 @@ </span><span class="cx"> for task in element.childtasks: </span><span class="cx"> header(buf, _indent() + " |- Save subelements of UOWTaskElement(%s)\n" % id(element)) </span><span class="cx"> task._dump(buf, indent + 1) </span><del>- for dep in self.dependencies: - header(buf, _indent() + " |- Save dependencies\n") - _dump_processor(dep, False) - for dep in self.dependencies: - header(buf, _indent() + " |- Delete dependencies\n") - _dump_processor(dep, True) </del><ins>+ _dump_dependencies(self) </ins><span class="cx"> for dep in self.cyclical_dependencies: </span><span class="cx"> header(buf, _indent() + " |- Cyclical Delete dependencies\n") </span><span class="cx"> _dump_processor(dep, True) </span><del>- for child in self.childtasks: - header(buf, _indent() + " |- Child tasks\n") - child._dump(buf, indent + 1) -# for obj in self.postupdate: -# header(buf, _indent() + " |- Post Update objects\n") -# buf.write(_repr(obj) + "\n") </del><ins>+ _dump_childtasks(self) </ins><span class="cx"> for element in self.todelete_elements: </span><span class="cx"> for task in element.childtasks: </span><span class="cx"> header(buf, _indent() + " |- Delete subelements of UOWTaskElement(%s)\n" % id(element)) </span><span class="cx"> task._dump(buf, indent + 1) </span><ins>+ _dump_deleteelements(self) </ins><span class="cx"> </span><del>- for rec in self.todelete_elements: - if rec.listonly: - continue - header(buf, _indent() + " |- Delete elements\n") - buf.write(_indent() + " |- " + _repr_task_element(rec) + "\n") - </del><span class="cx"> if self.is_empty(): </span><span class="cx"> buf.write(_indent() + " |- (empty task)\n") </span><span class="cx"> else: </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-05-25 16:24:05
|
<!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>[1509] sqlalchemy/trunk/test/testbase.py: correction to running single named tests</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1509</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-05-25 11:23:39 -0500 (Thu, 25 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>correction to running single named tests</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunktesttestbasepy">sqlalchemy/trunk/test/testbase.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunktesttestbasepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/test/testbase.py (1508 => 1509)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/test/testbase.py 2006-05-25 15:02:59 UTC (rev 1508) +++ sqlalchemy/trunk/test/testbase.py 2006-05-25 16:23:39 UTC (rev 1509) </span><span class="lines">@@ -349,7 +349,12 @@ </span><span class="cx"> runner.run(suite) </span><span class="cx"> </span><span class="cx"> def main(): </span><del>- suite = unittest.TestLoader().loadTestsFromModule(__import__('__main__')) </del><ins>+ if len(sys.argv[1:]): + suite =unittest.TestLoader().loadTestsFromNames(sys.argv[1:], __import__('__main__')) + else: + suite = unittest.TestLoader().loadTestsFromModule(__import__('__main__')) + + </ins><span class="cx"> runTests(suite) </span><span class="cx"> </span><span class="cx"> </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-05-25 15:17:16
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head><style type="text/css"><!-- #msg dl { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; } #msg dt { float: left; width: 6em; font-weight: bold; } #msg dt:after { content:':';} #msg dl, #msg dt, #msg ul, #msg li { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; } #msg dl a { font-weight: bold} #msg dl a:link { color:#fc3; } #msg dl a:active { color:#ff0; } #msg dl a:visited { color:#cc6; } h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; } #msg pre { overflow: auto; background: #ffc; border: 1px #fc0 solid; padding: 6px; } #msg ul, pre { overflow: auto; } #patch { width: 100%; } #patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;} #patch .propset h4, #patch .binary h4 {margin:0;} #patch pre {padding:0;line-height:1.2em;margin:0;} #patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;} #patch .propset .diff, #patch .binary .diff {padding:10px 0;} #patch span {display:block;padding:0 10px;} #patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;} #patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;} #patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;} #patch .lines, .info {color:#888;background:#fff;} --></style> <title>[1508] sqlalchemy/trunk/lib/sqlalchemy/orm/query.py: workaround for get that requires multiple ids in the case of joined table inheritance</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1508</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-05-25 10:02:59 -0500 (Thu, 25 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>workaround for get that requires multiple ids in the case of joined table inheritance</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunklibsqlalchemyormquerypy">sqlalchemy/trunk/lib/sqlalchemy/orm/query.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunklibsqlalchemyormquerypy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/orm/query.py (1507 => 1508)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/orm/query.py 2006-05-25 14:48:32 UTC (rev 1507) +++ sqlalchemy/trunk/lib/sqlalchemy/orm/query.py 2006-05-25 15:02:59 UTC (rev 1508) </span><span class="lines">@@ -267,7 +267,13 @@ </span><span class="cx"> params = {} </span><span class="cx"> for primary_key in self.mapper.pks_by_table[self.table]: </span><span class="cx"> params["pk_"+primary_key.key] = ident[i] </span><del>- i += 1 </del><ins>+ # if there are not enough elements in the given identifier, then + # use the previous identifier repeatedly. this is a workaround for the issue + # in [ticket:185], where a mapper that uses joined table inheritance needs to specify + # all primary keys of the joined relationship, which includes even if the join is joining + # two primary key (and therefore synonymous) columns together, the usual case for joined table inheritance. + if len(ident) > i + 1: + i += 1 </ins><span class="cx"> try: </span><span class="cx"> statement = self._compile(self._get_clause) </span><span class="cx"> return self._select_statement(statement, params=params, populate_existing=reload)[0] </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-05-25 14:48: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>[1507] sqlalchemy/trunk: added 0.1.7 changes to changelog</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1507</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-05-25 09:48:32 -0500 (Thu, 25 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>added 0.1.7 changes to changelog latest sqlsoup from 0.1.7 s. cazzells fixes to assignmapper, threadlocal</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunkCHANGES">sqlalchemy/trunk/CHANGES</a></li> <li><a href="#sqlalchemytrunklibsqlalchemyextassignmapperpy">sqlalchemy/trunk/lib/sqlalchemy/ext/assignmapper.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemyextsqlsouppy">sqlalchemy/trunk/lib/sqlalchemy/ext/sqlsoup.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemymodsthreadlocalpy">sqlalchemy/trunk/lib/sqlalchemy/mods/threadlocal.py</a></li> <li><a href="#sqlalchemytrunksetuppy">sqlalchemy/trunk/setup.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunkCHANGES"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/CHANGES (1506 => 1507)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/CHANGES 2006-05-25 14:20:23 UTC (rev 1506) +++ sqlalchemy/trunk/CHANGES 2006-05-25 14:48:32 UTC (rev 1507) </span><span class="lines">@@ -50,6 +50,35 @@ </span><span class="cx"> runner to insure its properly working. docs generally overhauled to </span><span class="cx"> deal with new code patterns </span><span class="cx"> </span><ins>+0.1.7 +- some fixes to topological sort algorithm +- added DISTINCT ON support to Postgres (just supply distinct=[col1,col2..]) +- added __mod__ (% operator) to sql expressions +- "order_by" mapper property inherited from inheriting mapper +- fix to column type used when mapper UPDATES/DELETEs +- with convert_unicode=True, reflection was failing, has been fixed +- types types types! still werent working....have to use TypeDecorator again :( +- mysql binary type converts array output to buffer, fixes PickleType +- fixed the attributes.py memory leak once and for all +- unittests are qualified based on the databases that support each one +- fixed bug where column defaults would clobber VALUES clause of insert objects +- fixed bug where table def w/ schema name would force engine connection +- fix for parenthesis to work correctly with subqueries in INSERT/UPDATE +- HistoryArraySet gets extend() method +- fixed lazyload support for other comparison operators besides = +- lazyload fix where two comparisons in the join condition point to the +samem column +- added "construct_new" flag to mapper, will use __new__ to create instances +instead of __init__ (standard in 0.2) +- added selectresults.py to SVN, missed it last time +- tweak to allow a many-to-many relationship from a table to itself via +an association table +- small fix to "translate_row" function used by polymorphic example +- create_engine uses cgi.parse_qsl to read query string (out the window in 0.2) +- tweaks to CAST operator +- fixed function names LOCAL_TIME/LOCAL_TIMESTAMP -> LOCALTIME/LOCALTIMESTAMP +- fixed order of ORDER BY/HAVING in compile + </ins><span class="cx"> 0.1.6 </span><span class="cx"> - support for MS-SQL added courtesy Rick Morrison, Runar Petursson </span><span class="cx"> - the latest SQLSoup from J. Ellis </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemyextassignmapperpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/ext/assignmapper.py (1506 => 1507)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/ext/assignmapper.py 2006-05-25 14:20:23 UTC (rev 1506) +++ sqlalchemy/trunk/lib/sqlalchemy/ext/assignmapper.py 2006-05-25 14:48:32 UTC (rev 1507) </span><span class="lines">@@ -10,6 +10,9 @@ </span><span class="cx"> def monkeypatch_objectstore_method(ctx, class_, name): </span><span class="cx"> def do(self, *args, **kwargs): </span><span class="cx"> session = ctx.current </span><ins>+ if name == "flush": + # flush expects a list of objects + self = [self] </ins><span class="cx"> return getattr(session, name)(self, *args, **kwargs) </span><span class="cx"> setattr(class_, name, do) </span><span class="cx"> </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemyextsqlsouppy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/ext/sqlsoup.py (1506 => 1507)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/ext/sqlsoup.py 2006-05-25 14:20:23 UTC (rev 1506) +++ sqlalchemy/trunk/lib/sqlalchemy/ext/sqlsoup.py 2006-05-25 14:48:32 UTC (rev 1507) </span><span class="lines">@@ -1,72 +1,182 @@ </span><del>-from sqlalchemy import * - -class NoSuchTableError(SQLAlchemyError): pass - -# metaclass is necessary to expose class methods with getattr, e.g. -# we want to pass db.users.select through to users._mapper.select -class TableClassType(type): - def insert(cls, **kwargs): - o = cls() - o.__dict__.update(kwargs) - return o - def __getattr__(cls, attr): - if attr == '_mapper': - # called during mapper init - raise AttributeError() - return getattr(cls._mapper, attr) - -def class_for_table(table): - klass = TableClassType('Class_' + table.name.capitalize(), (object,), {}) - def __repr__(self): - import locale - encoding = locale.getdefaultlocale()[1] - L = [] - for k in self.__class__.c.keys(): - value = getattr(self, k, '') - if isinstance(value, unicode): - value = value.encode(encoding) - L.append("%s=%r" % (k, value)) - return '%s(%s)' % (self.__class__.__name__, ','.join(L)) - klass.__repr__ = __repr__ - klass._mapper = mapper(klass, table) - return klass - -class SqlSoup: - def __init__(self, *args, **kwargs): - """ - args may either be an SQLEngine or a set of arguments suitable - for passing to create_engine - """ - from sqlalchemy.sql import Engine - # meh, sometimes having method overloading instead of kwargs would be easier - if isinstance(args[0], Engine): - engine = args.pop(0) - if args or kwargs: - raise ArgumentError('Extra arguments not allowed when engine is given') - else: - engine = create_engine(*args, **kwargs) - self._engine = engine - self._cache = {} - def delete(self, *args, **kwargs): - objectstore.delete(*args, **kwargs) - def commit(self): - objectstore.get_session().commit() - def rollback(self): - objectstore.clear() - def _reset(self): - # for debugging - self._cache = {} - self.rollback() - def __getattr__(self, attr): - try: - t = self._cache[attr] - except KeyError: - table = Table(attr, self._engine, autoload=True) - if table.columns: - t = class_for_table(table) - else: - t = None - self._cache[attr] = t - if not t: - raise NoSuchTableError('%s does not exist' % attr) - return t </del><ins>+from sqlalchemy import * + +""" +SqlSoup provides a convenient way to access database tables without having +to declare table or mapper classes ahead of time. + +Suppose we have a database with users, books, and loans tables +(corresponding to the PyWebOff dataset, if you're curious). +For testing purposes, we can create this db as follows: + +>>> from sqlalchemy import create_engine +>>> e = create_engine('sqlite://filename=:memory:') +>>> for sql in _testsql: e.execute(sql) +... + +Creating a SqlSoup gateway is just like creating an SqlAlchemy engine: +>>> from sqlalchemy.ext.sqlsoup import SqlSoup +>>> soup = SqlSoup('sqlite://filename=:memory:') + +or, you can re-use an existing engine: +>>> soup = SqlSoup(e) + +Loading objects is as easy as this: +>>> users = soup.users.select() +>>> users.sort() +>>> users +[Class_Users(name='Bhargan Basepair',email='bas...@ex...',password='basepair',classname=None,admin=1), Class_Users(name='Joe Student',email='st...@ex...',password='student',classname=None,admin=0)] + +Of course, letting the database do the sort is better (".c" is short for ".columns"): +>>> soup.users.select(order_by=[soup.users.c.name]) +[Class_Users(name='Bhargan Basepair',email='bas...@ex...',password='basepair',classname=None,admin=1), + Class_Users(name='Joe Student',email='st...@ex...',password='student',classname=None,admin=0)] + +Field access is intuitive: +>>> users[0].email +u'bas...@ex...' + +Of course, you don't want to load all users very often. The common case is to +select by a key or other field: +>>> soup.users.selectone_by(name='Bhargan Basepair') +Class_Users(name='Bhargan Basepair',email='bas...@ex...',password='basepair',classname=None,admin=1) + +All the SqlAlchemy mapper select variants (select, select_by, selectone, selectone_by, selectfirst, selectfirst_by) +are available. See the SqlAlchemy documentation for details: +http://www.sqlalchemy.org/docs/sqlconstruction.myt + +Modifying objects is intuitive: +>>> user = _ +>>> user.email = 'bas...@ex...' +>>> soup.commit() + +(SqlSoup leverages the sophisticated SqlAlchemy unit-of-work code, so +multiple updates to a single object will be turned into a single UPDATE +statement when you commit.) + +Finally, insert and delete. Let's insert a new loan, then delete it: +>>> soup.loans.insert(book_id=soup.books.selectfirst().id, user_name=user.name) +Class_Loans(book_id=1,user_name='Bhargan Basepair',loan_date=None) +>>> soup.commit() + +>>> loan = soup.loans.selectone_by(book_id=1, user_name='Bhargan Basepair') +>>> soup.delete(loan) +>>> soup.commit() +""" + +_testsql = """ +CREATE TABLE books ( + id integer PRIMARY KEY, -- auto-SERIAL in sqlite + title text NOT NULL, + published_year char(4) NOT NULL, + authors text NOT NULL +); + +CREATE TABLE users ( + name varchar(32) PRIMARY KEY, + email varchar(128) NOT NULL, + password varchar(128) NOT NULL, + classname text, + admin int NOT NULL -- 0 = false +); + +CREATE TABLE loans ( + book_id int PRIMARY KEY REFERENCES books(id), + user_name varchar(32) references users(name) + ON DELETE SET NULL ON UPDATE CASCADE, + loan_date date NOT NULL DEFAULT current_timestamp +); + +insert into users(name, email, password, admin) +values('Bhargan Basepair', 'bas...@ex...', 'basepair', 1); +insert into users(name, email, password, admin) +values('Joe Student', 'st...@ex...', 'student', 0); + +insert into books(title, published_year, authors) +values('Mustards I Have Known', '1989', 'Jones'); +insert into books(title, published_year, authors) +values('Regional Variation in Moss', '1971', 'Flim and Flam'); + +insert into loans(book_id, user_name) +values ( + (select min(id) from books), + (select name from users where name like 'Joe%')) +; +""".split(';') + +__all__ = ['NoSuchTableError', 'SqlSoup'] + +class NoSuchTableError(SQLAlchemyError): pass + +# metaclass is necessary to expose class methods with getattr, e.g. +# we want to pass db.users.select through to users._mapper.select +class TableClassType(type): + def insert(cls, **kwargs): + o = cls() + o.__dict__.update(kwargs) + return o + def __getattr__(cls, attr): + if attr == '_mapper': + # called during mapper init + raise AttributeError() + return getattr(cls._mapper, attr) + +def class_for_table(table): + klass = TableClassType('Class_' + table.name.capitalize(), (object,), {}) + def __repr__(self): + import locale + encoding = locale.getdefaultlocale()[1] + L = [] + for k in self.__class__.c.keys(): + value = getattr(self, k, '') + if isinstance(value, unicode): + value = value.encode(encoding) + L.append("%s=%r" % (k, value)) + return '%s(%s)' % (self.__class__.__name__, ','.join(L)) + klass.__repr__ = __repr__ + klass._mapper = mapper(klass, table) + return klass + +class SqlSoup: + def __init__(self, *args, **kwargs): + """ + args may either be an SQLEngine or a set of arguments suitable + for passing to create_engine + """ + from sqlalchemy.engine import SQLEngine + # meh, sometimes having method overloading instead of kwargs would be easier + if isinstance(args[0], SQLEngine): + args = list(args) + engine = args.pop(0) + if args or kwargs: + raise ArgumentError('Extra arguments not allowed when engine is given') + else: + engine = create_engine(*args, **kwargs) + self._engine = engine + self._cache = {} + def delete(self, *args, **kwargs): + objectstore.delete(*args, **kwargs) + def commit(self): + objectstore.get_session().commit() + def rollback(self): + objectstore.clear() + def _reset(self): + # for debugging + self._cache = {} + self.rollback() + def __getattr__(self, attr): + try: + t = self._cache[attr] + except KeyError: + table = Table(attr, self._engine, autoload=True) + if table.columns: + t = class_for_table(table) + else: + t = None + self._cache[attr] = t + if not t: + raise NoSuchTableError('%s does not exist' % attr) + return t + +if __name__ == '__main__': + import doctest + doctest.testmod() </ins></span></pre></div> <a id="sqlalchemytrunklibsqlalchemymodsthreadlocalpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/mods/threadlocal.py (1506 => 1507)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/mods/threadlocal.py 2006-05-25 14:20:23 UTC (rev 1506) +++ sqlalchemy/trunk/lib/sqlalchemy/mods/threadlocal.py 2006-05-25 14:48:32 UTC (rev 1507) </span><span class="lines">@@ -29,18 +29,15 @@ </span><span class="cx"> def assign_mapper(class_, *args, **kwargs): </span><span class="cx"> assignmapper.assign_mapper(objectstore, class_, *args, **kwargs) </span><span class="cx"> </span><del>-def _mapper_extension(): - return SessionContext._get_mapper_extension(objectstore) - </del><span class="cx"> objectstore = Objectstore(Session) </span><span class="cx"> def install_plugin(): </span><span class="cx"> sqlalchemy.objectstore = objectstore </span><del>- global_extensions.append(_mapper_extension) </del><ins>+ global_extensions.append(objectstore.mapper_extension) </ins><span class="cx"> engine.default_strategy = 'threadlocal' </span><span class="cx"> sqlalchemy.assign_mapper = assign_mapper </span><span class="cx"> </span><span class="cx"> def uninstall_plugin(): </span><span class="cx"> engine.default_strategy = 'plain' </span><del>- global_extensions.remove(_mapper_extension) </del><ins>+ global_extensions.remove(objectstore.mapper_extension) </ins><span class="cx"> </span><span class="cx"> install_plugin() </span></span></pre></div> <a id="sqlalchemytrunksetuppy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/setup.py (1506 => 1507)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/setup.py 2006-05-25 14:20:23 UTC (rev 1506) +++ sqlalchemy/trunk/setup.py 2006-05-25 14:48:32 UTC (rev 1507) </span><span class="lines">@@ -3,7 +3,7 @@ </span><span class="cx"> from setuptools import setup, find_packages </span><span class="cx"> </span><span class="cx"> setup(name = "SQLAlchemy", </span><del>- version = "0.1.6", </del><ins>+ version = "0.2.0alpha", </ins><span class="cx"> description = "Database Abstraction Library", </span><span class="cx"> author = "Mike Bayer", </span><span class="cx"> author_email = "mi...@zz...", </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-05-25 14:12: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>[1505] sqlalchemy/branches/rel_0_1/: 0.1 maintenance branch</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1505</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-05-25 09:12:47 -0500 (Thu, 25 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>0.1 maintenance branch</pre> <h3>Added Paths</h3> <ul> <li>sqlalchemy/branches/rel_0_1/</li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesrel_0_1fromrev1504sqlalchemytrunk"></a> <div class="copfile"><h4>Copied: sqlalchemy/branches/rel_0_1 (from rev 1504, sqlalchemy/trunk) ( => )</h4> <pre class="diff"><span> <span class="info"> </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-05-25 00:38:42
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head><style type="text/css"><!-- #msg dl { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; } #msg dt { float: left; width: 6em; font-weight: bold; } #msg dt:after { content:':';} #msg dl, #msg dt, #msg ul, #msg li { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; } #msg dl a { font-weight: bold} #msg dl a:link { color:#fc3; } #msg dl a:active { color:#ff0; } #msg dl a:visited { color:#cc6; } h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; } #msg pre { overflow: auto; background: #ffc; border: 1px #fc0 solid; padding: 6px; } #msg ul, pre { overflow: auto; } #patch { width: 100%; } #patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;} #patch .propset h4, #patch .binary h4 {margin:0;} #patch pre {padding:0;line-height:1.2em;margin:0;} #patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;} #patch .propset .diff, #patch .binary .diff {padding:10px 0;} #patch span {display:block;padding:0 10px;} #patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;} #patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;} #patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;} #patch .lines, .info {color:#888;background:#fff;} --></style> <title>[1504] sqlalchemy/branches/schema/test/testbase.py: echo fix</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1504</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-05-24 19:38:29 -0500 (Wed, 24 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>echo fix</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesschematesttestbasepy">sqlalchemy/branches/schema/test/testbase.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschematesttestbasepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/test/testbase.py (1503 => 1504)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/test/testbase.py 2006-05-25 00:37:16 UTC (rev 1503) +++ sqlalchemy/branches/schema/test/testbase.py 2006-05-25 00:38:29 UTC (rev 1504) </span><span class="lines">@@ -12,6 +12,7 @@ </span><span class="cx"> db = None </span><span class="cx"> metadata = None </span><span class="cx"> db_uri = None </span><ins>+echo = True </ins><span class="cx"> </span><span class="cx"> # redefine sys.stdout so all those print statements go to the echo func </span><span class="cx"> local_stdout = sys.stdout </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-05-25 00:37:35
|
<!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>[1503] sqlalchemy/branches/schema/test: echo print statement stuff</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1503</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-05-24 19:37:16 -0500 (Wed, 24 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>echo print statement stuff</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesschematestalltestspy">sqlalchemy/branches/schema/test/alltests.py</a></li> <li><a href="#sqlalchemybranchesschematestdefaultspy">sqlalchemy/branches/schema/test/defaults.py</a></li> <li><a href="#sqlalchemybranchesschematestindexespy">sqlalchemy/branches/schema/test/indexes.py</a></li> <li><a href="#sqlalchemybranchesschematesttestbasepy">sqlalchemy/branches/schema/test/testbase.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschematestalltestspy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/test/alltests.py (1502 => 1503)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/test/alltests.py 2006-05-24 22:46:59 UTC (rev 1502) +++ sqlalchemy/branches/schema/test/alltests.py 2006-05-25 00:37:16 UTC (rev 1503) </span><span class="lines">@@ -1,17 +1,13 @@ </span><span class="cx"> import testbase </span><span class="cx"> import unittest </span><span class="cx"> </span><del>-testbase.echo = False - -#test - </del><span class="cx"> def suite(): </span><span class="cx"> modules_to_test = ( </span><span class="cx"> # core utilities </span><del>- 'historyarray', </del><ins>+ 'historyarray', </ins><span class="cx"> 'attributes', </span><span class="cx"> 'dependency', </span><del>- </del><ins>+ </ins><span class="cx"> # connectivity, execution </span><span class="cx"> 'pool', </span><span class="cx"> 'transaction', </span><span class="lines">@@ -66,8 +62,6 @@ </span><span class="cx"> alltests.addTest(unittest.findTestCases(module, suiteClass=None)) </span><span class="cx"> return alltests </span><span class="cx"> </span><del>-import sys -sys.stdout = sys.stderr </del><span class="cx"> </span><span class="cx"> if __name__ == '__main__': </span><span class="cx"> testbase.runTests(suite()) </span></span></pre></div> <a id="sqlalchemybranchesschematestdefaultspy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/test/defaults.py (1502 => 1503)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/test/defaults.py 2006-05-24 22:46:59 UTC (rev 1502) +++ sqlalchemy/branches/schema/test/defaults.py 2006-05-25 00:37:16 UTC (rev 1503) </span><span class="lines">@@ -7,7 +7,7 @@ </span><span class="cx"> import sqlalchemy </span><span class="cx"> </span><span class="cx"> db = testbase.db </span><del>-testbase.echo=False </del><ins>+ </ins><span class="cx"> class DefaultTest(PersistTest): </span><span class="cx"> </span><span class="cx"> def setUpAll(self): </span></span></pre></div> <a id="sqlalchemybranchesschematestindexespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/test/indexes.py (1502 => 1503)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/test/indexes.py 2006-05-24 22:46:59 UTC (rev 1502) +++ sqlalchemy/branches/schema/test/indexes.py 2006-05-25 00:37:16 UTC (rev 1503) </span><span class="lines">@@ -67,7 +67,6 @@ </span><span class="cx"> stream = dummy() </span><span class="cx"> stream.write = capt.append </span><span class="cx"> testbase.db.logger = testbase.db.engine.logger = stream </span><del>- </del><span class="cx"> events = Table('events', metadata, </span><span class="cx"> Column('id', Integer, primary_key=True), </span><span class="cx"> Column('name', String(30), unique=True), </span></span></pre></div> <a id="sqlalchemybranchesschematesttestbasepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/test/testbase.py (1502 => 1503)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/test/testbase.py 2006-05-24 22:46:59 UTC (rev 1502) +++ sqlalchemy/branches/schema/test/testbase.py 2006-05-25 00:37:16 UTC (rev 1503) </span><span class="lines">@@ -9,13 +9,21 @@ </span><span class="cx"> import optparse </span><span class="cx"> </span><span class="cx"> </span><del>-echo = True -#echo = False -#echo = 'debug' </del><span class="cx"> db = None </span><span class="cx"> metadata = None </span><span class="cx"> db_uri = None </span><span class="cx"> </span><ins>+# redefine sys.stdout so all those print statements go to the echo func +local_stdout = sys.stdout +class Logger(object): + def write(self, msg): + if echo: + local_stdout.write(msg) +sys.stdout = Logger() + +def echo_text(text): + print text + </ins><span class="cx"> def parse_argv(): </span><span class="cx"> # we are using the unittest main runner, so we are just popping out the </span><span class="cx"> # arguments we need instead of using our own getopt type of thing </span><span class="lines">@@ -29,6 +37,8 @@ </span><span class="cx"> parser.add_option("--dburi", action="store", dest="dburi", help="database uri (overrides --db)") </span><span class="cx"> parser.add_option("--db", action="store", dest="db", default="sqlite", help="prefab database uri (sqlite, sqlite_file, postgres, mysql, oracle, oracle8, mssql)") </span><span class="cx"> parser.add_option("--mockpool", action="store_true", dest="mockpool", help="use mock pool") </span><ins>+ parser.add_option("--verbose", action="store_true", dest="verbose", help="full debug echoing") + parser.add_option("--quiet", action="store_true", dest="quiet", help="be totally quiet") </ins><span class="cx"> parser.add_option("--nothreadlocal", action="store_true", dest="nothreadlocal", help="dont use thread-local mod") </span><span class="cx"> parser.add_option("--enginestrategy", action="store", default=None, dest="enginestrategy", help="engine strategy (plain or threadlocal, defaults to SA default)") </span><span class="cx"> </span><span class="lines">@@ -66,12 +76,18 @@ </span><span class="cx"> __import__('sqlalchemy.mods.threadlocal') </span><span class="cx"> sqlalchemy.mods.threadlocal.uninstall_plugin() </span><span class="cx"> </span><ins>+ global echo + echo = options.verbose and not options.quiet + + global quiet + quiet = options.quiet + </ins><span class="cx"> if options.enginestrategy is not None: </span><span class="cx"> opts['strategy'] = options.enginestrategy </span><span class="cx"> if options.mockpool: </span><del>- db = engine.create_engine(db_uri, echo=echo, default_ordering=True, poolclass=MockPool, **opts) </del><ins>+ db = engine.create_engine(db_uri, echo=True, default_ordering=True, poolclass=MockPool, **opts) </ins><span class="cx"> else: </span><del>- db = engine.create_engine(db_uri, echo=echo, default_ordering=True, **opts) </del><ins>+ db = engine.create_engine(db_uri, echo=True, default_ordering=True, **opts) </ins><span class="cx"> db = EngineAssert(db) </span><span class="cx"> metadata = sqlalchemy.BoundMetaData(db) </span><span class="cx"> </span><span class="lines">@@ -103,16 +119,13 @@ </span><span class="cx"> return lala </span><span class="cx"> return decorate </span><span class="cx"> </span><del>-def echo_text(text): - print text </del><span class="cx"> </span><span class="cx"> class PersistTest(unittest.TestCase): </span><span class="cx"> """persist base class, provides default setUpAll, tearDownAll and echo functionality""" </span><span class="cx"> def __init__(self, *args, **params): </span><span class="cx"> unittest.TestCase.__init__(self, *args, **params) </span><span class="cx"> def echo(self, text): </span><del>- if echo: - echo_text(text) </del><ins>+ echo_text(text) </ins><span class="cx"> def install_threadlocal(self): </span><span class="cx"> sqlalchemy.mods.threadlocal.install_plugin() </span><span class="cx"> def uninstall_threadlocal(self): </span><span class="lines">@@ -121,8 +134,10 @@ </span><span class="cx"> pass </span><span class="cx"> def tearDownAll(self): </span><span class="cx"> pass </span><ins>+ def shortDescription(self): + """overridden to not return docstrings""" + return None </ins><span class="cx"> </span><del>- </del><span class="cx"> class MockPool(pool.Pool): </span><span class="cx"> """this pool is hardcore about only one connection being used at a time.""" </span><span class="cx"> def __init__(self, creator, **params): </span><span class="lines">@@ -329,10 +344,11 @@ </span><span class="cx"> </span><span class="cx"> </span><span class="cx"> def runTests(suite): </span><del>- runner = unittest.TextTestRunner(verbosity = 2, descriptions =1) </del><ins>+ runner = unittest.TextTestRunner(verbosity = quiet and 1 or 2) </ins><span class="cx"> runner.run(suite) </span><span class="cx"> </span><span class="cx"> def main(): </span><del>- unittest.main() </del><ins>+ suite = unittest.TestLoader().loadTestsFromModule(__import__('__main__')) + runTests(suite) </ins><span class="cx"> </span><span class="cx"> </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>[1502] sqlalchemy/branches/schema/lib/sqlalchemy/orm/unitofwork.py: dependency processing is more complete, checks carefully for individual objects that may have</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1502</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-05-24 17:46:59 -0500 (Wed, 24 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>dependency processing is more complete, checks carefully for individual objects that may have moved from "saved" to "deleted"</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemalibsqlalchemyormunitofworkpy">sqlalchemy/branches/schema/lib/sqlalchemy/orm/unitofwork.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschemalibsqlalchemyormunitofworkpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/unitofwork.py (1501 => 1502)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/unitofwork.py 2006-05-24 21:57:05 UTC (rev 1501) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/unitofwork.py 2006-05-24 22:46:59 UTC (rev 1502) </span><span class="lines">@@ -356,15 +356,11 @@ </span><span class="cx"> self._mark_modified() </span><span class="cx"> </span><span class="cx"> def execute(self, echo=False): </span><del>- # tell all related mappers to set up dependency processors - #for task in self.tasks.values(): - # task.mapper.register_dependencies(self) - </del><span class="cx"> # pre-execute dependency processors. this process may </span><del>- # result in new tasks and/or dependency processors being added, </del><ins>+ # result in new tasks, objects and/or dependency processors being added, </ins><span class="cx"> # particularly with 'delete-orphan' cascade rules. </span><del>- # keep running through the full list of tasks until no more - # new objects get processed. </del><ins>+ # keep running through the full list of tasks until all + # objects have been processed. </ins><span class="cx"> while True: </span><span class="cx"> ret = False </span><span class="cx"> for task in self.tasks.values(): </span><span class="lines">@@ -437,13 +433,41 @@ </span><span class="cx"> """an element within a UOWTask. corresponds to a single object instance </span><span class="cx"> to be saved, deleted, or just part of the transaction as a placeholder for </span><span class="cx"> further dependencies (i.e. 'listonly'). </span><del>- in the case of self-referential mappers, may also store a "childtask", which is a - UOWTask containing objects dependent on this element's object instance.""" </del><ins>+ in the case of self-referential mappers, may also store a list of childtasks, + further UOWTasks containing objects dependent on this element's object instance.""" </ins><span class="cx"> def __init__(self, obj): </span><span class="cx"> self.obj = obj </span><del>- self.listonly = True </del><ins>+ self.__listonly = True </ins><span class="cx"> self.childtasks = [] </span><del>- self.isdelete = False </del><ins>+ self.__isdelete = False + self.__preprocessed = {} + def _get_listonly(self): + return self.__listonly + def _set_listonly(self, value): + """set_listonly is a one-way setter, will only go from True to False.""" + if not value and self.__listonly: + self.__listonly = False + self.clear_preprocessed() + def _get_isdelete(self): + return self.__isdelete + def _set_isdelete(self, value): + if self.__isdelete is not value: + self.__isdelete = value + self.clear_preprocessed() + listonly = property(_get_listonly, _set_listonly) + isdelete = property(_get_isdelete, _set_isdelete) + + def mark_preprocessed(self, processor): + """marks this element as "preprocessed" by a particular UOWDependencyProcessor. preprocessing is the step + which sweeps through all the relationships on all the objects in the flush transaction and adds other objects + which are also affected, In some cases it can switch an object from "tosave" to "todelete". changes to the state + of this UOWTaskElement will reset all "preprocessed" flags, causing it to be preprocessed again. When all UOWTaskElements + have been fully preprocessed by all UOWDependencyProcessors, then the topological sort can be done.""" + self.__preprocessed[processor] = True + def is_preprocessed(self, processor): + return self.__preprocessed.get(processor, False) + def clear_preprocessed(self): + self.__preprocessed.clear() </ins><span class="cx"> def __repr__(self): </span><span class="cx"> return "UOWTaskElement/%d: %s/%d %s" % (id(self), self.obj.__class__.__name__, id(self.obj), (self.listonly and 'listonly' or (self.isdelete and 'delete' or 'save')) ) </span><span class="cx"> </span><span class="lines">@@ -454,27 +478,25 @@ </span><span class="cx"> def __init__(self, processor, targettask): </span><span class="cx"> self.processor = processor </span><span class="cx"> self.targettask = targettask </span><del>- self.preprocessed = Set() - </del><ins>+ </ins><span class="cx"> def preexecute(self, trans): </span><ins>+ """traverses all objects handled by this dependency processor and locates additional objects which should be + part of the transaction, such as those affected deletes, orphans to be deleted, etc. Returns True if any + objects were preprocessed, or False if no objects were preprocessed.""" + def getobj(elem): + elem.mark_preprocessed(self) + return elem.obj + </ins><span class="cx"> ret = False </span><del>- elements = [elem.obj for elem in self.targettask.tosave_elements if elem.obj is not None and elem.obj not in self.preprocessed] </del><ins>+ elements = [getobj(elem) for elem in self.targettask.tosave_elements if elem.obj is not None and not elem.is_preprocessed(self)] </ins><span class="cx"> if len(elements): </span><span class="cx"> ret = True </span><del>- todo = [] - for e in elements: - self.preprocessed.add(e) - todo.append(e) - self.processor.preprocess_dependencies(self.targettask, todo, trans, delete=False) </del><ins>+ self.processor.preprocess_dependencies(self.targettask, elements, trans, delete=False) </ins><span class="cx"> </span><del>- elements = [elem.obj for elem in self.targettask.todelete_elements if elem.obj is not None and elem.obj not in self.preprocessed] </del><ins>+ elements = [getobj(elem) for elem in self.targettask.todelete_elements if elem.obj is not None and not elem.is_preprocessed(self)] </ins><span class="cx"> if len(elements): </span><span class="cx"> ret = True </span><del>- todo = [] - for e in elements: - self.preprocessed.add(e) - todo.append(e) - self.processor.preprocess_dependencies(self.targettask, todo, trans, delete=True) </del><ins>+ self.processor.preprocess_dependencies(self.targettask, elements, trans, delete=True) </ins><span class="cx"> return ret </span><span class="cx"> </span><span class="cx"> def execute(self, trans, delete): </span><span class="lines">@@ -527,6 +549,8 @@ </span><span class="cx"> rec.childtasks.append(childtask) </span><span class="cx"> if isdelete: </span><span class="cx"> rec.isdelete = True </span><ins>+ #if not childtask: + # rec.preprocessed = False </ins><span class="cx"> return retval </span><span class="cx"> </span><span class="cx"> def append_postupdate(self, obj): </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-05-24 21:57: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>[1501] zblog/trunk/lib/zblog/database/mappers.py: echo_uow=False</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1501</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-05-24 16:57:05 -0500 (Wed, 24 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>echo_uow=False</pre> <h3>Modified Paths</h3> <ul> <li><a href="#zblogtrunklibzblogdatabasemapperspy">zblog/trunk/lib/zblog/database/mappers.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="zblogtrunklibzblogdatabasemapperspy"></a> <div class="modfile"><h4>Modified: zblog/trunk/lib/zblog/database/mappers.py (1500 => 1501)</h4> <pre class="diff"><span> <span class="info">--- zblog/trunk/lib/zblog/database/mappers.py 2006-05-24 21:56:41 UTC (rev 1500) +++ zblog/trunk/lib/zblog/database/mappers.py 2006-05-24 21:57:05 UTC (rev 1501) </span><span class="lines">@@ -131,7 +131,7 @@ </span><span class="cx"> </span><span class="cx"> def start_session(): </span><span class="cx"> """creates a new session for the start of a request.""" </span><del>- trans.session = create_session(bind_to=zblog.database.engine, echo_uow=True) </del><ins>+ trans.session = create_session(bind_to=zblog.database.engine, echo_uow=False) </ins><span class="cx"> </span><span class="cx"> def session(): </span><span class="cx"> return trans.session </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-05-24 21:56:53
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head><style type="text/css"><!-- #msg dl { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; } #msg dt { float: left; width: 6em; font-weight: bold; } #msg dt:after { content:':';} #msg dl, #msg dt, #msg ul, #msg li { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; } #msg dl a { font-weight: bold} #msg dl a:link { color:#fc3; } #msg dl a:active { color:#ff0; } #msg dl a:visited { color:#cc6; } h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; } #msg pre { overflow: auto; background: #ffc; border: 1px #fc0 solid; padding: 6px; } #msg ul, pre { overflow: auto; } #patch { width: 100%; } #patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;} #patch .propset h4, #patch .binary h4 {margin:0;} #patch pre {padding:0;line-height:1.2em;margin:0;} #patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;} #patch .propset .diff, #patch .binary .diff {padding:10px 0;} #patch span {display:block;padding:0 10px;} #patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;} #patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;} #patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;} #patch .lines, .info {color:#888;background:#fff;} --></style> <title>[1500] sqlalchemy/branches/schema/examples/adjacencytree/byroot_tree.py: full version</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1500</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-05-24 16:56:41 -0500 (Wed, 24 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>full version</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemaexamplesadjacencytreebyroot_treepy">sqlalchemy/branches/schema/examples/adjacencytree/byroot_tree.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschemaexamplesadjacencytreebyroot_treepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/examples/adjacencytree/byroot_tree.py (1499 => 1500)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/examples/adjacencytree/byroot_tree.py 2006-05-24 21:53:18 UTC (rev 1499) +++ sqlalchemy/branches/schema/examples/adjacencytree/byroot_tree.py 2006-05-24 21:56:41 UTC (rev 1500) </span><span class="lines">@@ -163,10 +163,10 @@ </span><span class="cx"> </span><span class="cx"> print node.print_nodes() </span><span class="cx"> </span><del>-#node.append('node4') -#node.children['node4'].append('subnode3') -#node.children['node4'].append('subnode4') -#node.children['node4'].children['subnode3'].append('subsubnode1') </del><ins>+node.append('node4') +node.children['node4'].append('subnode3') +node.children['node4'].append('subnode4') +node.children['node4'].children['subnode3'].append('subsubnode1') </ins><span class="cx"> del node.children['node1'] </span><span class="cx"> </span><span class="cx"> print "\n\n\n----------------------------" </span><span class="lines">@@ -181,7 +181,6 @@ </span><span class="cx"> print "Committing:" </span><span class="cx"> print "----------------------------" </span><span class="cx"> session.flush() </span><del>-sys.exit() </del><span class="cx"> </span><span class="cx"> print "\n\n\n----------------------------" </span><span class="cx"> print "Tree After Save:" </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-05-24 21:53:31
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head><style type="text/css"><!-- #msg dl { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; } #msg dt { float: left; width: 6em; font-weight: bold; } #msg dt:after { content:':';} #msg dl, #msg dt, #msg ul, #msg li { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; } #msg dl a { font-weight: bold} #msg dl a:link { color:#fc3; } #msg dl a:active { color:#ff0; } #msg dl a:visited { color:#cc6; } h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; } #msg pre { overflow: auto; background: #ffc; border: 1px #fc0 solid; padding: 6px; } #msg ul, pre { overflow: auto; } #patch { width: 100%; } #patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;} #patch .propset h4, #patch .binary h4 {margin:0;} #patch pre {padding:0;line-height:1.2em;margin:0;} #patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;} #patch .propset .diff, #patch .binary .diff {padding:10px 0;} #patch span {display:block;padding:0 10px;} #patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;} #patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;} #patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;} #patch .lines, .info {color:#888;background:#fff;} --></style> <title>[1499] sqlalchemy/branches/schema/test: more fixes to dependency sorting</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1499</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-05-24 16:53:18 -0500 (Wed, 24 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>more fixes to dependency sorting</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemalibsqlalchemyormdependencypy">sqlalchemy/branches/schema/lib/sqlalchemy/orm/dependency.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyormunitofworkpy">sqlalchemy/branches/schema/lib/sqlalchemy/orm/unitofwork.py</a></li> <li><a href="#sqlalchemybranchesschematestcascadepy">sqlalchemy/branches/schema/test/cascade.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschemalibsqlalchemyormdependencypy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/dependency.py (1498 => 1499)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/dependency.py 2006-05-24 18:42:09 UTC (rev 1498) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/dependency.py 2006-05-24 21:53:18 UTC (rev 1499) </span><span class="lines">@@ -359,6 +359,8 @@ </span><span class="cx"> for the many-to-many update task.""" </span><span class="cx"> def __init__(self, mapper): </span><span class="cx"> self.mapper = mapper </span><ins>+ def register_dependencies(self, uowcommit): + pass </ins><span class="cx"> def save_obj(self, *args, **kwargs): </span><span class="cx"> pass </span><span class="cx"> def delete_obj(self, *args, **kwargs): </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyormunitofworkpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/unitofwork.py (1498 => 1499)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/unitofwork.py 2006-05-24 18:42:09 UTC (rev 1498) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/unitofwork.py 2006-05-24 21:53:18 UTC (rev 1499) </span><span class="lines">@@ -325,7 +325,9 @@ </span><span class="cx"> try: </span><span class="cx"> return self.tasks[mapper] </span><span class="cx"> except KeyError: </span><del>- return UOWTask(self, mapper) </del><ins>+ task = UOWTask(self, mapper) + task.mapper.register_dependencies(self) + return task </ins><span class="cx"> </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="lines">@@ -355,8 +357,8 @@ </span><span class="cx"> </span><span class="cx"> def execute(self, echo=False): </span><span class="cx"> # tell all related mappers to set up dependency processors </span><del>- for task in self.tasks.values(): - task.mapper.register_dependencies(self) </del><ins>+ #for task in self.tasks.values(): + # task.mapper.register_dependencies(self) </ins><span class="cx"> </span><span class="cx"> # pre-execute dependency processors. this process may </span><span class="cx"> # result in new tasks and/or dependency processors being added, </span></span></pre></div> <a id="sqlalchemybranchesschematestcascadepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/test/cascade.py (1498 => 1499)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/test/cascade.py 2006-05-24 18:42:09 UTC (rev 1498) +++ sqlalchemy/branches/schema/test/cascade.py 2006-05-24 21:53:18 UTC (rev 1499) </span><span class="lines">@@ -7,13 +7,15 @@ </span><span class="cx"> class O2MCascadeTest(testbase.AssertMixin): </span><span class="cx"> def tearDown(self): </span><span class="cx"> ctx.current.clear() </span><ins>+ tables.delete() </ins><span class="cx"> </span><span class="cx"> def tearDownAll(self): </span><span class="cx"> clear_mappers() </span><del>- </del><ins>+ tables.drop() + </ins><span class="cx"> def setUpAll(self): </span><span class="cx"> global ctx, data </span><del>- ctx = SessionContext(create_session) </del><ins>+ ctx = SessionContext(lambda: create_session(echo_uow=True)) </ins><span class="cx"> tables.create() </span><span class="cx"> mapper(tables.User, tables.users, properties = dict( </span><span class="cx"> address = relation(mapper(tables.Address, tables.addresses), lazy = False, uselist = False, private = True), </span><span class="lines">@@ -71,11 +73,6 @@ </span><span class="cx"> ctx.current.flush() </span><span class="cx"> ctx.current.clear() </span><span class="cx"> </span><del>- def tearDown(self): - tables.delete() - - def tearDownAll(self): - clear_mappers() </del><span class="cx"> </span><span class="cx"> def testdelete(self): </span><span class="cx"> l = ctx.current.query(tables.User).select() </span><span class="lines">@@ -118,7 +115,8 @@ </span><span class="cx"> </span><span class="cx"> def tearDownAll(self): </span><span class="cx"> clear_mappers() </span><del>- </del><ins>+ metadata.drop_all() + </ins><span class="cx"> def setUpAll(self): </span><span class="cx"> global ctx, data, metadata, User, Pref </span><span class="cx"> ctx = SessionContext(create_session) </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-05-24 18:42:26
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head><style type="text/css"><!-- #msg dl { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; } #msg dt { float: left; width: 6em; font-weight: bold; } #msg dt:after { content:':';} #msg dl, #msg dt, #msg ul, #msg li { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; } #msg dl a { font-weight: bold} #msg dl a:link { color:#fc3; } #msg dl a:active { color:#ff0; } #msg dl a:visited { color:#cc6; } h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; } #msg pre { overflow: auto; background: #ffc; border: 1px #fc0 solid; padding: 6px; } #msg ul, pre { overflow: auto; } #patch { width: 100%; } #patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;} #patch .propset h4, #patch .binary h4 {margin:0;} #patch pre {padding:0;line-height:1.2em;margin:0;} #patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;} #patch .propset .diff, #patch .binary .diff {padding:10px 0;} #patch span {display:block;padding:0 10px;} #patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;} #patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;} #patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;} #patch .lines, .info {color:#888;background:#fff;} --></style> <title>[1498] sqlalchemy/branches/schema/test: added new cascade test, fixes to delete-orphan cascade rules (more probably needed)</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1498</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-05-24 13:42:09 -0500 (Wed, 24 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>added new cascade test, fixes to delete-orphan cascade rules (more probably needed)</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemaexamplesadjacencytreebasic_treepy">sqlalchemy/branches/schema/examples/adjacencytree/basic_tree.py</a></li> <li><a href="#sqlalchemybranchesschemaexamplesadjacencytreebyroot_treepy">sqlalchemy/branches/schema/examples/adjacencytree/byroot_tree.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyattributespy">sqlalchemy/branches/schema/lib/sqlalchemy/attributes.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyormdependencypy">sqlalchemy/branches/schema/lib/sqlalchemy/orm/dependency.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyormunitofworkpy">sqlalchemy/branches/schema/lib/sqlalchemy/orm/unitofwork.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyutilpy">sqlalchemy/branches/schema/lib/sqlalchemy/util.py</a></li> <li><a href="#sqlalchemybranchesschematestalltestspy">sqlalchemy/branches/schema/test/alltests.py</a></li> <li><a href="#sqlalchemybranchesschematestobjectstorepy">sqlalchemy/branches/schema/test/objectstore.py</a></li> </ul> <h3>Added Paths</h3> <ul> <li><a href="#sqlalchemybranchesschematestcascadepy">sqlalchemy/branches/schema/test/cascade.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschemaexamplesadjacencytreebasic_treepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/examples/adjacencytree/basic_tree.py (1497 => 1498)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/examples/adjacencytree/basic_tree.py 2006-05-24 16:35:30 UTC (rev 1497) +++ sqlalchemy/branches/schema/examples/adjacencytree/basic_tree.py 2006-05-24 18:42:09 UTC (rev 1498) </span><span class="lines">@@ -6,8 +6,6 @@ </span><span class="cx"> </span><span class="cx"> metadata = BoundMetaData('sqlite:///', echo=True) </span><span class="cx"> </span><del>-"""create the treenodes table. This is a basic adjacency list model table.""" - </del><span class="cx"> trees = Table('treenodes', metadata, </span><span class="cx"> Column('node_id', Integer, Sequence('treenode_id_seq',optional=False), primary_key=True), </span><span class="cx"> Column('parent_node_id', Integer, ForeignKey('treenodes.node_id'), nullable=True), </span><span class="lines">@@ -15,6 +13,7 @@ </span><span class="cx"> ) </span><span class="cx"> </span><span class="cx"> class NodeList(util.OrderedDict): </span><ins>+ """subclasses OrderedDict to allow usage as a list-based property.""" </ins><span class="cx"> def append(self, node): </span><span class="cx"> self[node.name] = node </span><span class="cx"> def __iter__(self): </span><span class="lines">@@ -77,7 +76,7 @@ </span><span class="cx"> print "Flushing:" </span><span class="cx"> print "----------------------------" </span><span class="cx"> </span><del>-session = create_session(echo_uow=True) </del><ins>+session = create_session() </ins><span class="cx"> session.save(node) </span><span class="cx"> session.flush() </span><span class="cx"> </span></span></pre></div> <a id="sqlalchemybranchesschemaexamplesadjacencytreebyroot_treepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/examples/adjacencytree/byroot_tree.py (1497 => 1498)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/examples/adjacencytree/byroot_tree.py 2006-05-24 16:35:30 UTC (rev 1497) +++ sqlalchemy/branches/schema/examples/adjacencytree/byroot_tree.py 2006-05-24 18:42:09 UTC (rev 1498) </span><span class="lines">@@ -2,10 +2,11 @@ </span><span class="cx"> import sqlalchemy.util as util </span><span class="cx"> import string, sys, time </span><span class="cx"> </span><del>-"""a more advanced example of basic_tree.py. illustrates MapperExtension objects which -add application-specific functionality to a Mapper object.""" </del><ins>+"""a more advanced example of basic_tree.py. treenodes can now reference their "root" node, and +introduces a new selection method which selects an entire tree of nodes at once, taking +advantage of a custom MapperExtension to assemble incoming nodes into their correct structure.""" </ins><span class="cx"> </span><del>-engine = create_engine('sqlite:///:memory:', echo = "debug") </del><ins>+engine = create_engine('sqlite:///:memory:', echo=True) </ins><span class="cx"> </span><span class="cx"> metadata = BoundMetaData(engine) </span><span class="cx"> </span><span class="lines">@@ -26,14 +27,10 @@ </span><span class="cx"> Column('data_id', Integer, primary_key=True), </span><span class="cx"> Column('value', String(100), nullable=False) </span><span class="cx"> ) </span><del>- </del><span class="cx"> </span><span class="cx"> </span><span class="cx"> class NodeList(util.OrderedDict): </span><del>- """extends an Ordered Dictionary, which is just a dictionary that iterates its keys and values - in the order they were inserted. Adds an "append" method, which appends a node to the - dictionary as though it were a list, and also within append automatically associates - the parent of a TreeNode with itself.""" </del><ins>+ """subclasses OrderedDict to allow usage as a list-based property.""" </ins><span class="cx"> def append(self, node): </span><span class="cx"> self[node.name] = node </span><span class="cx"> def __iter__(self): </span><span class="lines">@@ -120,18 +117,18 @@ </span><span class="cx"> print "Creating Tree Table:" </span><span class="cx"> print "----------------------------" </span><span class="cx"> </span><del>-treedata.create() -trees.create() </del><ins>+metadata.create_all() </ins><span class="cx"> </span><del>- </del><ins>+# the mapper is created with properties that specify "lazy=None" - this is because we are going +# to handle our own "eager load" of nodes based on root id </ins><span class="cx"> mapper(TreeNode, trees, properties=dict( </span><span class="cx"> id=trees.c.node_id, </span><span class="cx"> name=trees.c.node_name, </span><span class="cx"> parent_id=trees.c.parent_node_id, </span><span class="cx"> root_id=trees.c.root_node_id, </span><span class="cx"> root=relation(TreeNode, primaryjoin=trees.c.root_node_id==trees.c.node_id, foreignkey=trees.c.node_id, lazy=None, uselist=False), </span><del>- children=relation(TreeNode, primaryjoin=trees.c.parent_node_id==trees.c.node_id, lazy=None, uselist=True, cascade="delete,save-update"), - data=relation(mapper(TreeData, treedata, properties=dict(id=treedata.c.data_id)), cascade="delete,save-update", lazy=False) </del><ins>+ children=relation(TreeNode, primaryjoin=trees.c.parent_node_id==trees.c.node_id, lazy=None, uselist=True, cascade="delete,delete-orphan,save-update"), + data=relation(mapper(TreeData, treedata, properties=dict(id=treedata.c.data_id)), cascade="delete,delete-orphan,save-update", lazy=False) </ins><span class="cx"> </span><span class="cx"> ), extension = TreeLoader()) </span><span class="cx"> </span><span class="lines">@@ -166,10 +163,10 @@ </span><span class="cx"> </span><span class="cx"> print node.print_nodes() </span><span class="cx"> </span><del>-node.append('node4') -node.children['node4'].append('subnode3') -node.children['node4'].append('subnode4') -node.children['node4'].children['subnode3'].append('subsubnode1') </del><ins>+#node.append('node4') +#node.children['node4'].append('subnode3') +#node.children['node4'].append('subnode4') +#node.children['node4'].children['subnode3'].append('subsubnode1') </ins><span class="cx"> del node.children['node1'] </span><span class="cx"> </span><span class="cx"> print "\n\n\n----------------------------" </span><span class="lines">@@ -184,6 +181,7 @@ </span><span class="cx"> print "Committing:" </span><span class="cx"> print "----------------------------" </span><span class="cx"> session.flush() </span><ins>+sys.exit() </ins><span class="cx"> </span><span class="cx"> print "\n\n\n----------------------------" </span><span class="cx"> print "Tree After Save:" </span><span class="lines">@@ -199,6 +197,9 @@ </span><span class="cx"> print "----------------------------" </span><span class="cx"> </span><span class="cx"> session.clear() </span><ins>+ +# load some nodes. we do this based on "root id" which will load an entire sub-tree in one pass. +# the MapperExtension will assemble the incoming nodes into a tree structure. </ins><span class="cx"> t = session.query(TreeNode).select(TreeNode.c.root_id==nodeid, order_by=[TreeNode.c.id])[0] </span><span class="cx"> </span><span class="cx"> print "\n\n\n----------------------------" </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyattributespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/attributes.py (1497 => 1498)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/attributes.py 2006-05-24 16:35:30 UTC (rev 1497) +++ sqlalchemy/branches/schema/lib/sqlalchemy/attributes.py 2006-05-24 18:42:09 UTC (rev 1498) </span><span class="lines">@@ -131,8 +131,11 @@ </span><span class="cx"> if self.orig is ScalarAttribute.NONE: </span><span class="cx"> self.orig = orig </span><span class="cx"> self.obj.__dict__[self.key] = value </span><del>- if value is not None and self.trackparent: - self.sethasparent(value, True) </del><ins>+ if self.trackparent: + if value is not None: + self.sethasparent(value, True) + if orig is not None: + self.sethasparent(orig, False) </ins><span class="cx"> if self.extension is not None: </span><span class="cx"> self.extension.set(self.obj, value, orig) </span><span class="cx"> self.value_changed(orig, value) </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyormdependencypy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/dependency.py (1497 => 1498)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/dependency.py 2006-05-24 16:35:30 UTC (rev 1497) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/dependency.py 2006-05-24 18:42:09 UTC (rev 1498) </span><span class="lines">@@ -117,7 +117,6 @@ </span><span class="cx"> if child is not None and self.post_update: </span><span class="cx"> uowcommit.register_object(child, postupdate=True) </span><span class="cx"> for child in childlist.deleted_items(): </span><del>- print "HI KEY", self.key, "OBJECT", obj, "CHILD", child </del><span class="cx"> if not self.cascade.delete_orphan: </span><span class="cx"> self._synchronize(obj, child, None, True) </span><span class="cx"> </span><span class="lines">@@ -137,9 +136,13 @@ </span><span class="cx"> for child in childlist.deleted_items(): </span><span class="cx"> if child is not None and childlist.hasparent(child) is False: </span><span class="cx"> uowcommit.register_object(child, isdelete=True) </span><ins>+ for c in self.mapper.cascade_iterator('delete', child): + uowcommit.register_object(c, isdelete=True) </ins><span class="cx"> for child in childlist.unchanged_items(): </span><span class="cx"> if child is not None: </span><span class="cx"> uowcommit.register_object(child, isdelete=True) </span><ins>+ for c in self.mapper.cascade_iterator('delete', child): + uowcommit.register_object(c, isdelete=True) </ins><span class="cx"> else: </span><span class="cx"> for obj in deplist: </span><span class="cx"> childlist = self.get_object_dependencies(obj, uowcommit, passive=False) </span><span class="lines">@@ -158,10 +161,11 @@ </span><span class="cx"> uowcommit.register_object(child) </span><span class="cx"> for child in childlist.deleted_items(): </span><span class="cx"> if not self.cascade.delete_orphan: </span><del>- print "PREPROCESS KEY", self.key, "OBJECT", obj, "CHILD", child </del><span class="cx"> uowcommit.register_object(child, isdelete=False) </span><span class="cx"> elif childlist.hasparent(child) is False: </span><span class="cx"> uowcommit.register_object(child, isdelete=True) </span><ins>+ for c in self.mapper.cascade_iterator('delete', child): + uowcommit.register_object(c, isdelete=True) </ins><span class="cx"> </span><span class="cx"> def _synchronize(self, obj, child, associationrow, clearkeys): </span><span class="cx"> source = obj </span><span class="lines">@@ -205,17 +209,25 @@ </span><span class="cx"> if self.post_update: </span><span class="cx"> return </span><span class="cx"> if delete: </span><del>- if self.cascade.delete_orphan: </del><ins>+ if self.cascade.delete: </ins><span class="cx"> for obj in deplist: </span><span class="cx"> childlist = self.get_object_dependencies(obj, uowcommit, passive=False) </span><span class="cx"> for child in childlist.deleted_items() + childlist.unchanged_items(): </span><span class="cx"> if child is not None and childlist.hasparent(child) is False: </span><span class="cx"> uowcommit.register_object(child, isdelete=True) </span><ins>+ for c in self.mapper.cascade_iterator('delete', child): + uowcommit.register_object(c, isdelete=True) </ins><span class="cx"> else: </span><span class="cx"> for obj in deplist: </span><del>- childlist = self.get_object_dependencies(obj, uowcommit, passive=True) </del><span class="cx"> uowcommit.register_object(obj) </span><del>- </del><ins>+ if self.cascade.delete_orphan: + childlist = self.get_object_dependencies(obj, uowcommit, passive=False) + for child in childlist.deleted_items(): + if childlist.hasparent(child) is False: + uowcommit.register_object(child, isdelete=True) + for c in self.mapper.cascade_iterator('delete', child): + uowcommit.register_object(c, isdelete=True) + </ins><span class="cx"> def _synchronize(self, obj, child, associationrow, clearkeys): </span><span class="cx"> source = child </span><span class="cx"> dest = obj </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyormunitofworkpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/unitofwork.py (1497 => 1498)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/unitofwork.py 2006-05-24 16:35:30 UTC (rev 1497) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/unitofwork.py 2006-05-24 18:42:09 UTC (rev 1498) </span><span class="lines">@@ -351,13 +351,31 @@ </span><span class="cx"> targettask = self.get_task_by_mapper(mapperfrom) </span><span class="cx"> up = UOWDependencyProcessor(processor, targettask) </span><span class="cx"> task.dependencies.append(up) </span><del>- up.preexecute(self) </del><span class="cx"> self._mark_modified() </span><span class="cx"> </span><span class="cx"> def execute(self, echo=False): </span><ins>+ # tell all related mappers to set up dependency processors </ins><span class="cx"> for task in self.tasks.values(): </span><span class="cx"> task.mapper.register_dependencies(self) </span><span class="cx"> </span><ins>+ # pre-execute dependency processors. this process may + # result in new tasks and/or dependency processors being added, + # particularly with 'delete-orphan' cascade rules. + # keep running through the full list of tasks until no more + # new objects get processed. + while True: + ret = False + for task in self.tasks.values(): + for up in task.dependencies: + if up.preexecute(self): + ret = True + if not ret: + break + + # flip the execution flag on. in some test cases + # we like to check this flag against any new objects being added, since everything + # should be registered by now. there is a slight exception in the case of + # post_update requests; this should be fixed. </ins><span class="cx"> self.__is_executing = True </span><span class="cx"> </span><span class="cx"> head = self._sort_dependencies() </span><span class="lines">@@ -434,10 +452,28 @@ </span><span class="cx"> def __init__(self, processor, targettask): </span><span class="cx"> self.processor = processor </span><span class="cx"> self.targettask = targettask </span><ins>+ self.preprocessed = Set() </ins><span class="cx"> </span><span class="cx"> def preexecute(self, trans): </span><del>- self.processor.preprocess_dependencies(self.targettask, [elem.obj for elem in self.targettask.tosave_elements if elem.obj is not None], trans, delete=False) - self.processor.preprocess_dependencies(self.targettask, [elem.obj for elem in self.targettask.todelete_elements if elem.obj is not None], trans, delete=True) </del><ins>+ ret = False + elements = [elem.obj for elem in self.targettask.tosave_elements if elem.obj is not None and elem.obj not in self.preprocessed] + if len(elements): + ret = True + todo = [] + for e in elements: + self.preprocessed.add(e) + todo.append(e) + self.processor.preprocess_dependencies(self.targettask, todo, trans, delete=False) + + elements = [elem.obj for elem in self.targettask.todelete_elements if elem.obj is not None and elem.obj not in self.preprocessed] + if len(elements): + ret = True + todo = [] + for e in elements: + self.preprocessed.add(e) + todo.append(e) + self.processor.preprocess_dependencies(self.targettask, todo, trans, delete=True) + return ret </ins><span class="cx"> </span><span class="cx"> def execute(self, trans, delete): </span><span class="cx"> if not delete: </span><span class="lines">@@ -468,7 +504,7 @@ </span><span class="cx"> </span><span class="cx"> def is_empty(self): </span><span class="cx"> return len(self.objects) == 0 and len(self.dependencies) == 0 and len(self.childtasks) == 0 </span><del>- </del><ins>+ </ins><span class="cx"> def append(self, obj, listonly = False, childtask = None, isdelete = False): </span><span class="cx"> """appends an object to this task, to be either saved or deleted depending on the </span><span class="cx"> 'isdelete' attribute of this UOWTask. 'listonly' indicates that the object should </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyutilpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/util.py (1497 => 1498)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/util.py 2006-05-24 16:35:30 UTC (rev 1497) +++ sqlalchemy/branches/schema/lib/sqlalchemy/util.py 2006-05-24 18:42:09 UTC (rev 1498) </span><span class="lines">@@ -367,6 +367,7 @@ </span><span class="cx"> self.__delrecord(self.data[i]) </span><span class="cx"> del self.data[i] </span><span class="cx"> def __setslice__(self, i, j, other): </span><ins>+ print "HAS SETSLICE" </ins><span class="cx"> i = max(i, 0); j = max(j, 0) </span><span class="cx"> if isinstance(other, UserList.UserList): </span><span class="cx"> l = other.data </span><span class="lines">@@ -374,6 +375,7 @@ </span><span class="cx"> l = other </span><span class="cx"> else: </span><span class="cx"> l = list(other) </span><ins>+ [self.__delrecord(x) for x in self.data[i:]] </ins><span class="cx"> g = [a for a in l if self.__setrecord(a)] </span><span class="cx"> self.data[i:] = g </span><span class="cx"> def __delslice__(self, i, j): </span></span></pre></div> <a id="sqlalchemybranchesschematestalltestspy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/test/alltests.py (1497 => 1498)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/test/alltests.py 2006-05-24 16:35:30 UTC (rev 1497) +++ sqlalchemy/branches/schema/test/alltests.py 2006-05-24 18:42:09 UTC (rev 1498) </span><span class="lines">@@ -42,6 +42,7 @@ </span><span class="cx"> # ORM persistence </span><span class="cx"> 'sessioncontext', </span><span class="cx"> 'objectstore', </span><ins>+ 'cascade', </ins><span class="cx"> 'relationships', </span><span class="cx"> </span><span class="cx"> # cyclical ORM persistence </span></span></pre></div> <a id="sqlalchemybranchesschematestcascadepy"></a> <div class="addfile"><h4>Added: sqlalchemy/branches/schema/test/cascade.py (1497 => 1498)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/test/cascade.py 2006-05-24 16:35:30 UTC (rev 1497) +++ sqlalchemy/branches/schema/test/cascade.py 2006-05-24 18:42:09 UTC (rev 1498) </span><span class="lines">@@ -0,0 +1,175 @@ </span><ins>+import testbase, tables +import unittest, sys, datetime + +from sqlalchemy.ext.sessioncontext import SessionContext +from sqlalchemy import * + +class O2MCascadeTest(testbase.AssertMixin): + def tearDown(self): + ctx.current.clear() + + def tearDownAll(self): + clear_mappers() + + def setUpAll(self): + global ctx, data + ctx = SessionContext(create_session) + tables.create() + mapper(tables.User, tables.users, properties = dict( + address = relation(mapper(tables.Address, tables.addresses), lazy = False, uselist = False, private = True), + orders = relation( + mapper(tables.Order, tables.orders, properties = dict ( + items = relation(mapper(tables.Item, tables.orderitems), lazy = False, uselist =True, private = True) + )), + lazy = True, uselist = True, private = True) + )) + + def setUp(self): + global data + data = [tables.User, + {'user_name' : 'ed', + 'address' : (tables.Address, {'email_address' : 'fo...@ba...'}), + 'orders' : (tables.Order, [ + {'description' : 'eds 1st order', 'items' : (tables.Item, [{'item_name' : 'eds o1 item'}, {'item_name' : 'eds other o1 item'}])}, + {'description' : 'eds 2nd order', 'items' : (tables.Item, [{'item_name' : 'eds o2 item'}, {'item_name' : 'eds other o2 item'}])} + ]) + }, + {'user_name' : 'jack', + 'address' : (tables.Address, {'email_address' : 'ja...@ja...'}), + 'orders' : (tables.Order, [ + {'description' : 'jacks 1st order', 'items' : (tables.Item, [{'item_name' : 'im a lumberjack'}, {'item_name' : 'and im ok'}])} + ]) + }, + {'user_name' : 'foo', + 'address' : (tables.Address, {'email_address': 'hi...@la...'}), + 'orders' : (tables.Order, [ + {'description' : 'foo order', 'items' : (tables.Item, [])}, + {'description' : 'foo order 2', 'items' : (tables.Item, [{'item_name' : 'hi'}])}, + {'description' : 'foo order three', 'items' : (tables.Item, [{'item_name' : 'there'}])} + ]) + } + ] + + for elem in data[1:]: + u = tables.User() + ctx.current.save(u) + u.user_name = elem['user_name'] + u.address = tables.Address() + u.address.email_address = elem['address'][1]['email_address'] + u.orders = [] + for order in elem['orders'][1]: + o = tables.Order() + o.isopen = None + o.description = order['description'] + u.orders.append(o) + o.items = [] + for item in order['items'][1]: + i = tables.Item() + i.item_name = item['item_name'] + o.items.append(i) + + ctx.current.flush() + ctx.current.clear() + + def tearDown(self): + tables.delete() + + def tearDownAll(self): + clear_mappers() + + def testdelete(self): + l = ctx.current.query(tables.User).select() + for u in l: + self.echo( repr(u.orders)) + self.assert_result(l, data[0], *data[1:]) + + self.echo("\n\n\n") + ids = (l[0].user_id, l[2].user_id) + ctx.current.delete(l[0]) + ctx.current.delete(l[2]) + + ctx.current.flush() + self.assert_(tables.orders.count(tables.orders.c.user_id.in_(*ids)).scalar() == 0) + self.assert_(tables.orderitems.count(tables.orders.c.user_id.in_(*ids) &(tables.orderitems.c.order_id==tables.orders.c.order_id)).scalar() == 0) + self.assert_(tables.addresses.count(tables.addresses.c.user_id.in_(*ids)).scalar() == 0) + self.assert_(tables.users.count(tables.users.c.user_id.in_(*ids)).scalar() == 0) + + + def testorphan(self): + l = ctx.current.query(tables.User).select() + jack = l[1] + jack.orders[:] = [] + + ids = [jack.user_id] + self.assert_(tables.orders.count(tables.orders.c.user_id.in_(*ids)).scalar() == 1) + self.assert_(tables.orderitems.count(tables.orders.c.user_id.in_(*ids) &(tables.orderitems.c.order_id==tables.orders.c.order_id)).scalar() == 2) + + ctx.current.flush() + + self.assert_(tables.orders.count(tables.orders.c.user_id.in_(*ids)).scalar() == 0) + self.assert_(tables.orderitems.count(tables.orders.c.user_id.in_(*ids) &(tables.orderitems.c.order_id==tables.orders.c.order_id)).scalar() == 0) + + +class M2OCascadeTest(testbase.AssertMixin): + def tearDown(self): + ctx.current.clear() + for t in metadata.table_iterator(reverse=True): + t.delete().execute() + + def tearDownAll(self): + clear_mappers() + + def setUpAll(self): + global ctx, data, metadata, User, Pref + ctx = SessionContext(create_session) + metadata = BoundMetaData(testbase.db) + prefs = Table('prefs', metadata, + Column('prefs_id', Integer, Sequence('prefs_id_seq', optional=True), primary_key=True), + Column('prefs_data', String(40))) + + users = Table('users', metadata, + Column('user_id', Integer, Sequence('user_id_seq', optional=True), primary_key = True), + Column('user_name', String(40)), + Column('pref_id', Integer, ForeignKey('prefs.prefs_id')) + ) + class User(object): + pass + class Pref(object): + pass + metadata.create_all() + mapper(User, users, properties = dict( + pref = relation(mapper(Pref, prefs), lazy=False, cascade="all, delete-orphan") + )) + + def setUp(self): + global data + data = [User, + {'user_name' : 'ed', + 'pref' : (Pref, {'prefs_data' : 'pref 1'}), + }, + {'user_name' : 'jack', + 'pref' : (Pref, {'prefs_data' : 'pref 2'}), + }, + {'user_name' : 'foo', + 'pref' : (Pref, {'prefs_data' : 'pref 3'}), + } + ] + + for elem in data[1:]: + u = User() + ctx.current.save(u) + u.user_name = elem['user_name'] + u.pref = Pref() + u.pref.prefs_data = elem['pref'][1]['prefs_data'] + + ctx.current.flush() + ctx.current.clear() + + def testorphan(self): + l = ctx.current.query(User).select() + jack = l[1] + jack.pref = None + ctx.current.flush() + +if __name__ == "__main__": + testbase.main() </ins></span></pre></div> <a id="sqlalchemybranchesschematestobjectstorepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/test/objectstore.py (1497 => 1498)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/test/objectstore.py 2006-05-24 16:35:30 UTC (rev 1497) +++ sqlalchemy/branches/schema/test/objectstore.py 2006-05-24 18:42:09 UTC (rev 1498) </span><span class="lines">@@ -591,84 +591,7 @@ </span><span class="cx"> ctx.current.delete(u) </span><span class="cx"> ctx.current.flush() </span><span class="cx"> self.assert_(a.address_id is not None and a.user_id is None and not ctx.current.identity_map.has_key(u._instance_key) and ctx.current.identity_map.has_key(a._instance_key)) </span><del>- - def testcascadingdelete(self): - m = mapper(User, users, properties = dict( - address = relation(mapper(Address, addresses), lazy = False, uselist = False, private = True), - orders = relation( - mapper(Order, orders, properties = dict ( - items = relation(mapper(Item, orderitems), lazy = False, uselist =True, private = True) - )), - lazy = True, uselist = True, private = True) - )) - - data = [User, - {'user_name' : 'ed', - 'address' : (Address, {'email_address' : 'fo...@ba...'}), - 'orders' : (Order, [ - {'description' : 'eds 1st order', 'items' : (Item, [{'item_name' : 'eds o1 item'}, {'item_name' : 'eds other o1 item'}])}, - {'description' : 'eds 2nd order', 'items' : (Item, [{'item_name' : 'eds o2 item'}, {'item_name' : 'eds other o2 item'}])} - ]) - }, - {'user_name' : 'jack', - 'address' : (Address, {'email_address' : 'ja...@ja...'}), - 'orders' : (Order, [ - {'description' : 'jacks 1st order', 'items' : (Item, [{'item_name' : 'im a lumberjack'}, {'item_name' : 'and im ok'}])} - ]) - }, - {'user_name' : 'foo', - 'address' : (Address, {'email_address': 'hi...@la...'}), - 'orders' : (Order, [ - {'description' : 'foo order', 'items' : (Item, [])}, - {'description' : 'foo order 2', 'items' : (Item, [{'item_name' : 'hi'}])}, - {'description' : 'foo order three', 'items' : (Item, [{'item_name' : 'there'}])} - ]) - } - ] </del><span class="cx"> </span><del>- for elem in data[1:]: - u = User() - u.user_name = elem['user_name'] - u.address = Address() - u.address.email_address = elem['address'][1]['email_address'] - u.orders = [] - for order in elem['orders'][1]: - o = Order() - o.isopen = None - o.description = order['description'] - u.orders.append(o) - o.items = [] - for item in order['items'][1]: - i = Item() - i.item_name = item['item_name'] - o.items.append(i) - - ctx.current.flush() - ctx.current.clear() - - l = m.select() - for u in l: - self.echo( repr(u.orders)) - self.assert_result(l, data[0], *data[1:]) - - self.echo("\n\n\n") - ctx.current.delete(l[0], l[2]) - ctx.current.flush() - return - res = self.capture_exec(db, lambda: ctx.current.flush()) - state = None - - for line in res.split('\n'): - if line == "DELETE FROM items WHERE items.item_id = :item_id": - self.assert_(state is None or state == 'addresses') - elif line == "DELETE FROM orders WHERE orders.order_id = :order_id": - state = 'orders' - elif line == "DELETE FROM email_addresses WHERE email_addresses.address_id = :address_id": - if state is None: - state = 'addresses' - elif line == "DELETE FROM users WHERE users.user_id = :user_id": - self.assert_(state is not None) - </del><span class="cx"> def testbackwardsonetoone(self): </span><span class="cx"> # test 'backwards' </span><span class="cx"> # m = mapper(Address, addresses, properties = dict( </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-05-24 16:35: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>[1497] sqlalchemy/trunk/lib/sqlalchemy: added explicit check for "==null()" to produce IS NULL, documnted "==None", "==null()", [ticket:187]</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1497</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-05-24 11:35:30 -0500 (Wed, 24 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>added explicit check for "==null()" to produce IS NULL, documnted "==None", "==null()", [ticket:187]</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunkdocbuildcontentsqlconstructiontxt">sqlalchemy/trunk/doc/build/content/sqlconstruction.txt</a></li> <li><a href="#sqlalchemytrunklibsqlalchemysqlpy">sqlalchemy/trunk/lib/sqlalchemy/sql.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunkdocbuildcontentsqlconstructiontxt"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/doc/build/content/sqlconstruction.txt (1496 => 1497)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/doc/build/content/sqlconstruction.txt 2006-05-24 16:30:56 UTC (rev 1496) +++ sqlalchemy/trunk/doc/build/content/sqlconstruction.txt 2006-05-24 16:35:30 UTC (rev 1497) </span><span class="lines">@@ -274,6 +274,18 @@ </span><span class="cx"> # any custom operator </span><span class="cx"> select([users.c.user_name.op('||')('_category')]) </span><span class="cx"> </span><ins>+ # "null" comparison via == (converts to IS) + {sql}users.select(users.c.user_name==None).execute() + SELECT users.user_id, users.user_name, users.password + FROM users + WHERE users.user_name IS NULL + + # or via explicit null() construct + {sql}users.select(users.c.user_name==null()).execute() + SELECT users.user_id, users.user_name, users.password + FROM users + WHERE users.user_name IS NULL + </ins><span class="cx"> #### Specifying the Engine {@name=engine} </span><span class="cx"> </span><span class="cx"> For queries that don't contain any tables, the SQLEngine can be specified to any constructed statement via the `engine` keyword parameter: </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemysqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/sql.py (1496 => 1497)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/sql.py 2006-05-24 16:30:56 UTC (rev 1496) +++ sqlalchemy/trunk/lib/sqlalchemy/sql.py 2006-05-24 16:35:30 UTC (rev 1497) </span><span class="lines">@@ -549,17 +549,16 @@ </span><span class="cx"> def _bind_param(self, obj): </span><span class="cx"> return BindParamClause('literal', obj, shortname=None, type=self.type) </span><span class="cx"> def _compare(self, operator, obj): </span><del>- if _is_literal(obj): - if obj is None: - if operator == '=': - return BooleanExpression(self._compare_self(), null(), 'IS') - elif operator == '!=': - return BooleanExpression(self._compare_self(), null(), 'IS NOT') - else: - raise exceptions.ArgumentError("Only '='/'!=' operators can be used with NULL") </del><ins>+ if obj is None or isinstance(obj, Null): + if operator == '=': </ins><span class="cx"> return BooleanExpression(self._compare_self(), null(), 'IS') </span><ins>+ elif operator == '!=': + return BooleanExpression(self._compare_self(), null(), 'IS NOT') + return BooleanExpression(self._compare_self(), null(), 'IS') </ins><span class="cx"> else: </span><del>- obj = self._bind_param(obj) </del><ins>+ raise exceptions.ArgumentError("Only '='/'!=' operators can be used with NULL") + elif _is_literal(obj): + obj = self._bind_param(obj) </ins><span class="cx"> return BooleanExpression(self._compare_self(), obj, operator, type=self._compare_type(obj)) </span><span class="cx"> def _operate(self, operator, obj): </span><span class="cx"> if _is_literal(obj): </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-05-24 16:31:12
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head><style type="text/css"><!-- #msg dl { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; } #msg dt { float: left; width: 6em; font-weight: bold; } #msg dt:after { content:':';} #msg dl, #msg dt, #msg ul, #msg li { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; } #msg dl a { font-weight: bold} #msg dl a:link { color:#fc3; } #msg dl a:active { color:#ff0; } #msg dl a:visited { color:#cc6; } h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; } #msg pre { overflow: auto; background: #ffc; border: 1px #fc0 solid; padding: 6px; } #msg ul, pre { overflow: auto; } #patch { width: 100%; } #patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;} #patch .propset h4, #patch .binary h4 {margin:0;} #patch pre {padding:0;line-height:1.2em;margin:0;} #patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;} #patch .propset .diff, #patch .binary .diff {padding:10px 0;} #patch span {display:block;padding:0 10px;} #patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;} #patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;} #patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;} #patch .lines, .info {color:#888;background:#fff;} --></style> <title>[1496] sqlalchemy/branches/schema/lib/sqlalchemy: documented IS NULL comparison, added extra check for "==null()" besides "==None", [ticket:187]</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1496</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-05-24 11:30:56 -0500 (Wed, 24 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>documented IS NULL comparison, added extra check for "==null()" besides "==None", [ticket:187]</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemadocbuildcontentsqlconstructiontxt">sqlalchemy/branches/schema/doc/build/content/sqlconstruction.txt</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemysqlpy">sqlalchemy/branches/schema/lib/sqlalchemy/sql.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschemadocbuildcontentsqlconstructiontxt"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/doc/build/content/sqlconstruction.txt (1495 => 1496)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/doc/build/content/sqlconstruction.txt 2006-05-24 16:16:37 UTC (rev 1495) +++ sqlalchemy/branches/schema/doc/build/content/sqlconstruction.txt 2006-05-24 16:30:56 UTC (rev 1496) </span><span class="lines">@@ -333,7 +333,18 @@ </span><span class="cx"> # any custom operator </span><span class="cx"> select([users.c.user_name.op('||')('_category')]) </span><span class="cx"> </span><ins>+ # "null" comparison via == (converts to IS) + {sql}users.select(users.c.user_name==None).execute() + SELECT users.user_id, users.user_name, users.password + FROM users + WHERE users.user_name IS NULL </ins><span class="cx"> </span><ins>+ # or via explicit null() construct + {sql}users.select(users.c.user_name==null()).execute() + SELECT users.user_id, users.user_name, users.password + FROM users + WHERE users.user_name IS NULL + </ins><span class="cx"> #### Functions {@name=functions} </span><span class="cx"> </span><span class="cx"> Functions can be specified using the `func` keyword: </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemysqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/sql.py (1495 => 1496)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/sql.py 2006-05-24 16:16:37 UTC (rev 1495) +++ sqlalchemy/branches/schema/lib/sqlalchemy/sql.py 2006-05-24 16:30:56 UTC (rev 1496) </span><span class="lines">@@ -570,16 +570,15 @@ </span><span class="cx"> def _bind_param(self, obj): </span><span class="cx"> return BindParamClause('literal', obj, shortname=None, type=self.type) </span><span class="cx"> def _compare(self, operator, obj): </span><del>- if _is_literal(obj): - if obj is None: - if operator == '=': - return BooleanExpression(self._compare_self(), null(), 'IS') - elif operator == '!=': - return BooleanExpression(self._compare_self(), null(), 'IS NOT') - else: - raise exceptions.ArgumentError("Only '='/'!=' operators can be used with NULL") </del><ins>+ if obj is None or isinstance(obj, Null): + if operator == '=': + return BooleanExpression(self._compare_self(), null(), 'IS') + elif operator == '!=': + return BooleanExpression(self._compare_self(), null(), 'IS NOT') </ins><span class="cx"> else: </span><del>- obj = self._bind_param(obj) </del><ins>+ raise exceptions.ArgumentError("Only '='/'!=' operators can be used with NULL") + elif _is_literal(obj): + obj = self._bind_param(obj) </ins><span class="cx"> </span><span class="cx"> return BooleanExpression(self._compare_self(), obj, operator, type=self._compare_type(obj)) </span><span class="cx"> def _operate(self, operator, obj): </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-05-24 16:16:57
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head><style type="text/css"><!-- #msg dl { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; } #msg dt { float: left; width: 6em; font-weight: bold; } #msg dt:after { content:':';} #msg dl, #msg dt, #msg ul, #msg li { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; } #msg dl a { font-weight: bold} #msg dl a:link { color:#fc3; } #msg dl a:active { color:#ff0; } #msg dl a:visited { color:#cc6; } h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; } #msg pre { overflow: auto; background: #ffc; border: 1px #fc0 solid; padding: 6px; } #msg ul, pre { overflow: auto; } #patch { width: 100%; } #patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;} #patch .propset h4, #patch .binary h4 {margin:0;} #patch pre {padding:0;line-height:1.2em;margin:0;} #patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;} #patch .propset .diff, #patch .binary .diff {padding:10px 0;} #patch span {display:block;padding:0 10px;} #patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;} #patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;} #patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;} #patch .lines, .info {color:#888;background:#fff;} --></style> <title>[1495] sqlalchemy/branches/schema/doc/build/content: added after_delete mapperextension call</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1495</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-05-24 11:16:37 -0500 (Wed, 24 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>added after_delete mapperextension call</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemadocbuildcontentadv_datamappingtxt">sqlalchemy/branches/schema/doc/build/content/adv_datamapping.txt</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyormmapperpy">sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschemadocbuildcontentadv_datamappingtxt"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/doc/build/content/adv_datamapping.txt (1494 => 1495)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/doc/build/content/adv_datamapping.txt 2006-05-24 02:22:42 UTC (rev 1494) +++ sqlalchemy/branches/schema/doc/build/content/adv_datamapping.txt 2006-05-24 16:16:37 UTC (rev 1495) </span><span class="lines">@@ -787,6 +787,8 @@ </span><span class="cx"> """called after an object instance has been INSERTed""" </span><span class="cx"> def before_delete(self, mapper, connection, instance): </span><span class="cx"> """called before an object instance is DELETEed""" </span><ins>+ def after_delete(self, mapper, connection, instance): + """called after an object instance is DELETEed""" </ins><span class="cx"> </span><span class="cx"> To use MapperExtension, make your own subclass of it and just send it off to a mapper: </span><span class="cx"> </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyormmapperpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py (1494 => 1495)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py 2006-05-24 02:22:42 UTC (rev 1494) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py 2006-05-24 16:16:37 UTC (rev 1495) </span><span class="lines">@@ -680,6 +680,7 @@ </span><span class="cx"> if not self._has_pks(table): </span><span class="cx"> continue </span><span class="cx"> delete = [] </span><ins>+ deleted_objects = [] </ins><span class="cx"> for obj in objects: </span><span class="cx"> params = {} </span><span class="cx"> if not hasattr(obj, "_instance_key"): </span><span class="lines">@@ -691,6 +692,7 @@ </span><span class="cx"> if self.version_id_col is not None: </span><span class="cx"> params[self.version_id_col.key] = self._getattrbycolumn(obj, self.version_id_col) </span><span class="cx"> self.extension.before_delete(self, connection, obj) </span><ins>+ deleted_objects.append(obj) </ins><span class="cx"> if len(delete): </span><span class="cx"> clause = sql.and_() </span><span class="cx"> for col in self.pks_by_table[table]: </span><span class="lines">@@ -701,6 +703,8 @@ </span><span class="cx"> c = connection.execute(statement, delete) </span><span class="cx"> if c.supports_sane_rowcount() and c.rowcount != len(delete): </span><span class="cx"> raise exceptions.FlushError("ConcurrencyError - updated rowcount %d does not match number of objects updated %d" % (c.cursor.rowcount, len(delete))) </span><ins>+ for obj in deleted_objects: + self.extension.after_delete(self, connection, obj) </ins><span class="cx"> </span><span class="cx"> def _has_pks(self, table): </span><span class="cx"> try: </span><span class="lines">@@ -1076,6 +1080,10 @@ </span><span class="cx"> """called before an object instance is DELETEed""" </span><span class="cx"> if self.next is not None: </span><span class="cx"> self.next.before_delete(mapper, connection, instance) </span><ins>+ def after_delete(self, mapper, connection, instance): + """called after an object instance is DELETEed""" + if self.next is not None: + self.next.after_delete(mapper, connection, instance) </ins><span class="cx"> </span><span class="cx"> class TranslatingDict(dict): </span><span class="cx"> """a dictionary that stores ColumnElement objects as keys. incoming ColumnElement </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-05-24 02:22:56
|
<!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>[1494] sqlalchemy/branches/schema/lib/sqlalchemy/orm: fixes to dependency refactor....better targeting for circular dep sort</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1494</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-05-23 21:22:42 -0500 (Tue, 23 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>fixes to dependency refactor....better targeting for circular dep sort</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemaexamplesadjacencytreebyroot_treepy">sqlalchemy/branches/schema/examples/adjacencytree/byroot_tree.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyormdependencypy">sqlalchemy/branches/schema/lib/sqlalchemy/orm/dependency.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyormmapperpy">sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyormunitofworkpy">sqlalchemy/branches/schema/lib/sqlalchemy/orm/unitofwork.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschemaexamplesadjacencytreebyroot_treepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/examples/adjacencytree/byroot_tree.py (1493 => 1494)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/examples/adjacencytree/byroot_tree.py 2006-05-23 23:57:29 UTC (rev 1493) +++ sqlalchemy/branches/schema/examples/adjacencytree/byroot_tree.py 2006-05-24 02:22:42 UTC (rev 1494) </span><span class="lines">@@ -5,7 +5,7 @@ </span><span class="cx"> """a more advanced example of basic_tree.py. illustrates MapperExtension objects which </span><span class="cx"> add application-specific functionality to a Mapper object.""" </span><span class="cx"> </span><del>-engine = create_engine('sqlite:///:memory:', echo = True) </del><ins>+engine = create_engine('sqlite:///:memory:', echo = "debug") </ins><span class="cx"> </span><span class="cx"> metadata = BoundMetaData(engine) </span><span class="cx"> </span><span class="lines">@@ -34,12 +34,7 @@ </span><span class="cx"> in the order they were inserted. Adds an "append" method, which appends a node to the </span><span class="cx"> dictionary as though it were a list, and also within append automatically associates </span><span class="cx"> the parent of a TreeNode with itself.""" </span><del>- def __init__(self, parent): - util.OrderedDict.__init__(self) - self.parent = parent </del><span class="cx"> def append(self, node): </span><del>- node.parent = self.parent - node._set_root(self.parent.root) </del><span class="cx"> self[node.name] = node </span><span class="cx"> def __iter__(self): </span><span class="cx"> return iter(self.values()) </span><span class="lines">@@ -54,12 +49,13 @@ </span><span class="cx"> identifiable root. Any node can return its root node and therefore the "tree" that it </span><span class="cx"> belongs to, and entire trees can be selected from the database in one query, by </span><span class="cx"> identifying their common root ID.""" </span><ins>+ children = NodeList </ins><span class="cx"> </span><span class="cx"> def __init__(self, name): </span><span class="cx"> """for data integrity, a TreeNode requires its name to be passed as a parameter </span><span class="cx"> to its constructor, so there is no chance of a TreeNode that doesnt have a name.""" </span><span class="cx"> self.name = name </span><del>- self.children = NodeList(self) </del><ins>+ self.children = NodeList() </ins><span class="cx"> self.root = self </span><span class="cx"> self.parent = None </span><span class="cx"> self.id = None </span><span class="lines">@@ -72,9 +68,10 @@ </span><span class="cx"> c._set_root(root) </span><span class="cx"> def append(self, node): </span><span class="cx"> if isinstance(node, str): </span><del>- self.children.append(TreeNode(node)) - else: - self.children.append(node) </del><ins>+ node = TreeNode(node) + node.parent = self + node._set_root(self.root) + self.children.append(node) </ins><span class="cx"> def __repr__(self): </span><span class="cx"> return self._getstring(0, False) </span><span class="cx"> def __str__(self): </span><span class="lines">@@ -89,19 +86,15 @@ </span><span class="cx"> </span><span class="cx"> class TreeLoader(MapperExtension): </span><span class="cx"> """an extension that will plug-in additional functionality to the Mapper.""" </span><del>- def create_instance(self, mapper, row, imap, class_): - """creates an instance of a TreeNode. since the TreeNode constructor requires - the 'name' argument, this method pulls the data from the database row directly.""" - return TreeNode(row[mapper.c.name], _mapper_nohistory=True) </del><span class="cx"> def after_insert(self, mapper, connection, instance): </span><span class="cx"> """runs after the insert of a new TreeNode row. The primary key of the row is not determined </span><span class="cx"> until the insert is complete, since most DB's use autoincrementing columns. If this node is </span><span class="cx"> the root node, we will take the new primary key and update it as the value of the node's </span><span class="cx"> "root ID" as well, since its root node is itself.""" </span><span class="cx"> if instance.root is instance: </span><del>- connection.execute(mapper.primarytable.update(TreeNode.c.id==instance.id, values=dict(root_node_id=instance.id))) </del><ins>+ connection.execute(mapper.mapped_table.update(TreeNode.c.id==instance.id, values=dict(root_node_id=instance.id))) </ins><span class="cx"> instance.root_id = instance.id </span><del>- def append_result(self, mapper, row, imap, result, instance, isnew, populate_existing=False): </del><ins>+ def append_result(self, mapper, session, row, imap, result, instance, isnew, populate_existing=False): </ins><span class="cx"> """runs as results from a SELECT statement are processed, and newly created or already-existing </span><span class="cx"> instances that correspond to each row are appended to result lists. This method will only </span><span class="cx"> append root nodes to the result list, and will attach child nodes to their appropriate parent </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyormdependencypy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/dependency.py (1493 => 1494)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/dependency.py 2006-05-23 23:57:29 UTC (rev 1493) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/dependency.py 2006-05-24 02:22:42 UTC (rev 1494) </span><span class="lines">@@ -117,6 +117,7 @@ </span><span class="cx"> if child is not None and self.post_update: </span><span class="cx"> uowcommit.register_object(child, postupdate=True) </span><span class="cx"> for child in childlist.deleted_items(): </span><ins>+ print "HI KEY", self.key, "OBJECT", obj, "CHILD", child </ins><span class="cx"> if not self.cascade.delete_orphan: </span><span class="cx"> self._synchronize(obj, child, None, True) </span><span class="cx"> </span><span class="lines">@@ -157,6 +158,7 @@ </span><span class="cx"> uowcommit.register_object(child) </span><span class="cx"> for child in childlist.deleted_items(): </span><span class="cx"> if not self.cascade.delete_orphan: </span><ins>+ print "PREPROCESS KEY", self.key, "OBJECT", obj, "CHILD", child </ins><span class="cx"> uowcommit.register_object(child, isdelete=False) </span><span class="cx"> elif childlist.hasparent(child) is False: </span><span class="cx"> uowcommit.register_object(child, isdelete=True) </span><span class="lines">@@ -179,7 +181,7 @@ </span><span class="cx"> uowcommit.register_dependency(self.mapper, self.parent) </span><span class="cx"> uowcommit.register_processor(self.mapper, self, self.parent) </span><span class="cx"> def process_dependencies(self, task, deplist, uowcommit, delete = False): </span><del>- #print self.mapper.table.name + " " + self.key + " " + repr(len(deplist)) + " process_dep isdelete " + repr(delete) + " direction " + repr(self.direction) </del><ins>+ #print self.mapper.mapped_table.name + " " + self.key + " " + repr(len(deplist)) + " process_dep isdelete " + repr(delete) + " direction " + repr(self.direction) </ins><span class="cx"> if delete: </span><span class="cx"> if self.post_update and not self.cascade.delete_orphan: </span><span class="cx"> # post_update means we have to update our row to not reference the child object </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyormmapperpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py (1493 => 1494)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py 2006-05-23 23:57:29 UTC (rev 1493) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py 2006-05-24 02:22:42 UTC (rev 1494) </span><span class="lines">@@ -227,10 +227,8 @@ </span><span class="cx"> # load properties from the main table object, </span><span class="cx"> # not overriding those set up in the 'properties' argument </span><span class="cx"> for column in self.mapped_table.columns: </span><del>- </del><span class="cx"> if self.columntoproperty.has_key(column): </span><span class="cx"> continue </span><del>- </del><span class="cx"> if not self.columns.has_key(column.key): </span><span class="cx"> self.columns[column.key] = column </span><span class="cx"> </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyormunitofworkpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/unitofwork.py (1493 => 1494)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/unitofwork.py 2006-05-23 23:57:29 UTC (rev 1493) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/unitofwork.py 2006-05-24 02:22:42 UTC (rev 1494) </span><span class="lines">@@ -607,11 +607,13 @@ </span><span class="cx"> # the task corresponding to the processor's objects </span><span class="cx"> childtask = trans.get_task_by_mapper(processor.mapper) </span><span class="cx"> </span><del>- if isdelete: - childlist = childlist.unchanged_items() + childlist.deleted_items() - else: - childlist = childlist.added_items() </del><ins>+# if isdelete: +# childlist = childlist.unchanged_items() + childlist.deleted_items() +# else: +# childlist = childlist.added_items() </ins><span class="cx"> </span><ins>+ childlist = childlist.added_items() + childlist.unchanged_items() + childlist.deleted_items() + </ins><span class="cx"> for o in childlist: </span><span class="cx"> if o is None or o not in childtask.objects: </span><span class="cx"> continue </span><span class="lines">@@ -621,9 +623,9 @@ </span><span class="cx"> # create a UOWDependencyProcessor representing this pair of objects. </span><span class="cx"> # append it to a UOWTask </span><span class="cx"> if whosdep[0] is obj: </span><del>- get_dependency_task(obj, dep).append(whosdep[0], isdelete=isdelete) </del><ins>+ get_dependency_task(whosdep[0], dep).append(whosdep[0], isdelete=isdelete) </ins><span class="cx"> else: </span><del>- get_dependency_task(obj, dep).append(whosdep[1], isdelete=isdelete) </del><ins>+ get_dependency_task(whosdep[0], dep).append(whosdep[1], isdelete=isdelete) </ins><span class="cx"> else: </span><span class="cx"> get_dependency_task(obj, dep).append(obj, isdelete=isdelete) </span><span class="cx"> </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>[1493] sqlalchemy/branches/schema/test: dependency processor refactored into four separate classes to deal with different relationship styles independently, avoid excessive if/else calls</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1493</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-05-23 18:57:29 -0500 (Tue, 23 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>dependency processor refactored into four separate classes to deal with different relationship styles independently, avoid excessive if/else calls simplifications to unitofwork, circular sorting pared down alot </pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemalibsqlalchemyormdependencypy">sqlalchemy/branches/schema/lib/sqlalchemy/orm/dependency.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyormpropertiespy">sqlalchemy/branches/schema/lib/sqlalchemy/orm/properties.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyormunitofworkpy">sqlalchemy/branches/schema/lib/sqlalchemy/orm/unitofwork.py</a></li> <li><a href="#sqlalchemybranchesschematestcyclespy">sqlalchemy/branches/schema/test/cycles.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschemalibsqlalchemyormdependencypy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/dependency.py (1492 => 1493)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/dependency.py 2006-05-23 15:40:29 UTC (rev 1492) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/dependency.py 2006-05-23 23:57:29 UTC (rev 1493) </span><span class="lines">@@ -11,6 +11,17 @@ </span><span class="cx"> from sync import ONETOMANY,MANYTOONE,MANYTOMANY </span><span class="cx"> from sqlalchemy import sql </span><span class="cx"> </span><ins>+def create_dependency_processor(key, syncrules, cascade, secondary=None, association=None, is_backref=False, post_update=False): + types = { + ONETOMANY : OneToManyDP, + MANYTOONE: ManyToOneDP, + MANYTOMANY : ManyToManyDP, + } + if association is not None: + return AssociationDP(key, syncrules, cascade, secondary, association, is_backref, post_update) + else: + return types[syncrules.direction](key, syncrules, cascade, secondary, association, is_backref, post_update) + </ins><span class="cx"> class DependencyProcessor(object): </span><span class="cx"> def __init__(self, key, syncrules, cascade, secondary=None, association=None, is_backref=False, post_update=False): </span><span class="cx"> # TODO: update instance variable names to be more meaningful </span><span class="lines">@@ -25,22 +36,6 @@ </span><span class="cx"> self.post_update = post_update </span><span class="cx"> self.key = key </span><span class="cx"> </span><del>- class MapperStub(object): - """poses as a Mapper representing the association table in a many-to-many - join, when performing a flush(). - - The Task objects in the objectstore module treat it just like - any other Mapper, but in fact it only serves as a "dependency" placeholder - for the many-to-many update task.""" - def __init__(self, mapper): - self.mapper = mapper - def save_obj(self, *args, **kwargs): - pass - def delete_obj(self, *args, **kwargs): - pass - def _primary_mapper(self): - return self - </del><span class="cx"> def register_dependencies(self, uowcommit): </span><span class="cx"> """tells a UOWTransaction what mappers are dependent on which, with regards </span><span class="cx"> to the two or three mappers handled by this PropertyLoader. </span><span class="lines">@@ -49,66 +44,8 @@ </span><span class="cx"> will be executed after that mapper's objects have been saved or before </span><span class="cx"> they've been deleted. The process operation manages attributes and dependent </span><span class="cx"> operations upon the objects of one of the involved mappers.""" </span><del>- if self.association is not None: - # association object. our mapper should be dependent on both - # the parent mapper and the association object mapper. - # this is where we put the "stub" as a marker, so we get - # association/parent->stub->self, then we process the child - # elments after the 'stub' save, which is before our own - # mapper's save. - stub = DependencyProcessor.MapperStub(self.association) - uowcommit.register_dependency(self.parent, stub) - uowcommit.register_dependency(self.association, stub) - uowcommit.register_dependency(stub, self.mapper) - uowcommit.register_processor(stub, self, self.parent, False) - uowcommit.register_processor(stub, self, self.parent, True) </del><ins>+ raise NotImplementedError() </ins><span class="cx"> </span><del>- elif self.direction == MANYTOMANY: - # many-to-many. create a "Stub" mapper to represent the - # "middle table" in the relationship. This stub mapper doesnt save - # or delete any objects, but just marks a dependency on the two - # related mappers. its dependency processor then populates the - # association table. - - if self.is_backref: - # if we are the "backref" half of a two-way backref - # relationship, let the other mapper handle inserting the rows - return - stub = DependencyProcessor.MapperStub(self.mapper) - uowcommit.register_dependency(self.parent, stub) - uowcommit.register_dependency(self.mapper, stub) - uowcommit.register_processor(stub, self, self.parent, False) - uowcommit.register_processor(stub, self, self.parent, True) - elif self.direction == ONETOMANY: - if self.post_update: - stub = DependencyProcessor.MapperStub(self.mapper) - uowcommit.register_dependency(self.mapper, stub) - uowcommit.register_dependency(self.parent, stub) - uowcommit.register_processor(stub, self, self.parent, False) - uowcommit.register_processor(stub, self, self.parent, True) - else: - uowcommit.register_dependency(self.parent, self.mapper) - uowcommit.register_processor(self.parent, self, self.parent, False) - uowcommit.register_processor(self.parent, self, self.parent, True) - elif self.direction == MANYTOONE: - if self.post_update: - stub = DependencyProcessor.MapperStub(self.mapper) - uowcommit.register_dependency(self.mapper, stub) - uowcommit.register_dependency(self.parent, stub) - uowcommit.register_processor(stub, self, self.parent, False) - uowcommit.register_processor(stub, self, self.parent, True) - else: - uowcommit.register_dependency(self.mapper, self.parent) - uowcommit.register_processor(self.mapper, self, self.parent, False) - uowcommit.register_processor(self.mapper, self, self.parent, True) - else: - raise AssertionError(" no foreign key ?") - - def get_object_dependencies(self, obj, uowcommit, passive = True): - """returns the list of objects that are dependent on the given object, as according to the relationship - this dependency processor represents""" - return uowcommit.uow.attributes.get_history(obj, self.key, passive = passive) - </del><span class="cx"> def whose_dependent_on_who(self, obj1, obj2): </span><span class="cx"> """given an object pair assuming obj2 is a child of obj1, returns a tuple </span><span class="cx"> with the dependent object second, or None if they are equal. </span><span class="lines">@@ -125,64 +62,42 @@ </span><span class="cx"> """this method is called during a flush operation to synchronize data between a parent and child object. </span><span class="cx"> it is called within the context of the various mappers and sometimes individual objects sorted according to their </span><span class="cx"> insert/update/delete order (topological sort).""" </span><del>- #print self.mapper.table.name + " " + self.key + " " + repr(len(deplist)) + " process_dep isdelete " + repr(delete) + " direction " + repr(self.direction) </del><ins>+ raise NotImplementedError() </ins><span class="cx"> </span><del>- def getlist(obj, passive=True): - return self.get_object_dependencies(obj, uowcommit, passive) </del><ins>+ def preprocess_dependencies(self, task, deplist, uowcommit, delete = False): + """used before the flushes' topological sort to traverse through related objects and insure every + instance which will require save/update/delete is properly added to the UOWTransaction.""" + raise NotImplementedError() </ins><span class="cx"> </span><del>- # plugin point </del><ins>+ def _synchronize(self, obj, child, associationrow, clearkeys): + """called during a flush to synchronize primary key identifier values between a parent/child object, as well as + to an associationrow in the case of many-to-many.""" + raise NotImplementedError() + + def get_object_dependencies(self, obj, uowcommit, passive = True): + """returns the list of objects that are dependent on the given object, as according to the relationship + this dependency processor represents""" + return uowcommit.uow.attributes.get_history(obj, self.key, passive = passive) </ins><span class="cx"> </span><del>- # TODO: process_dependencies has been refactored into two methods, process_dependencies and preprocess_dependencies. - # cleanup is still required to hone the method down to its minimal amount of code. - - if self.direction == MANYTOMANY: - connection = uowcommit.transaction.connection(self.mapper) - secondary_delete = [] - secondary_insert = [] - if delete: - for obj in deplist: - childlist = getlist(obj, False) - for child in childlist.deleted_items() + childlist.unchanged_items(): - associationrow = {} - self._synchronize(obj, child, associationrow, False) - secondary_delete.append(associationrow) - else: - for obj in deplist: - childlist = getlist(obj) - if childlist is None: continue - for child in childlist.added_items(): - associationrow = {} - self._synchronize(obj, child, associationrow, False) - secondary_insert.append(associationrow) - for child in childlist.deleted_items(): - associationrow = {} - self._synchronize(obj, child, associationrow, False) - secondary_delete.append(associationrow) - if len(secondary_delete): - # TODO: precompile the delete/insert queries and store them as instance variables - # on the PropertyLoader - statement = self.secondary.delete(sql.and_(*[c == sql.bindparam(c.key) for c in self.secondary.c])) - connection.execute(statement, secondary_delete) - if len(secondary_insert): - statement = self.secondary.insert() - connection.execute(statement, secondary_insert) - elif self.direction == MANYTOONE and delete: - if self.cascade.delete_orphan: - pass - elif self.post_update: - # post_update means we have to update our row to not reference the child object - # before we can DELETE the row - for obj in deplist: - self._synchronize(obj, None, None, True) - uowcommit.register_object(obj, postupdate=True) - elif self.direction == ONETOMANY and delete: </del><ins>+ +class OneToManyDP(DependencyProcessor): + def register_dependencies(self, uowcommit): + if self.post_update: + stub = MapperStub(self.mapper) + uowcommit.register_dependency(self.mapper, stub) + uowcommit.register_dependency(self.parent, stub) + uowcommit.register_processor(stub, self, self.parent) + else: + uowcommit.register_dependency(self.parent, self.mapper) + uowcommit.register_processor(self.parent, self, self.parent) + def process_dependencies(self, task, deplist, uowcommit, delete = False): + #print self.mapper.table.name + " " + self.key + " " + repr(len(deplist)) + " process_dep isdelete " + repr(delete) + " direction " + repr(self.direction) + if delete: </ins><span class="cx"> # head object is being deleted, and we manage its list of child objects </span><span class="cx"> # the child objects have to have their foreign key to the parent set to NULL </span><del>- if self.cascade.delete_orphan and not self.post_update: - pass - else: </del><ins>+ if not self.cascade.delete_orphan or self.post_update: </ins><span class="cx"> for obj in deplist: </span><del>- childlist = getlist(obj, False) </del><ins>+ childlist = self.get_object_dependencies(obj, uowcommit, passive=False) </ins><span class="cx"> for child in childlist.deleted_items(): </span><span class="cx"> if child is not None and childlist.hasparent(child) is False: </span><span class="cx"> self._synchronize(obj, child, None, True) </span><span class="lines">@@ -193,89 +108,31 @@ </span><span class="cx"> self._synchronize(obj, child, None, True) </span><span class="cx"> if self.post_update: </span><span class="cx"> uowcommit.register_object(child, postupdate=True) </span><del>- elif self.association is not None: - # manage association objects. - for obj in deplist: - childlist = getlist(obj, passive=True) - if childlist is None: continue - - #print "DIRECTION", self.direction - d = {} - for child in childlist: - self._synchronize(obj, child, None, False) - key = self.mapper.instance_key(child) - #print "SYNCHRONIZED", child, "INSTANCE KEY", key - d[key] = child - uowcommit.unregister_object(child) - - for child in childlist.added_items(): - uowcommit.register_object(child) - key = self.mapper.instance_key(child) - #print "ADDED, INSTANCE KEY", key - d[key] = child - - for child in childlist.unchanged_items(): - key = self.mapper.instance_key(child) - o = d[key] - o._instance_key= key - - for child in childlist.deleted_items(): - key = self.mapper.instance_key(child) - #print "DELETED, INSTANCE KEY", key - if d.has_key(key): - o = d[key] - o._instance_key = key - uowcommit.unregister_object(child) - else: - #print "DELETE ASSOC OBJ", repr(child) - uowcommit.register_object(child, isdelete=True) </del><span class="cx"> else: </span><span class="cx"> for obj in deplist: </span><del>- childlist = getlist(obj, passive=True) </del><ins>+ childlist = self.get_object_dependencies(obj, uowcommit, passive=True) </ins><span class="cx"> if childlist is not None: </span><span class="cx"> for child in childlist.added_items(): </span><span class="cx"> self._synchronize(obj, child, None, False) </span><del>- if self.direction == ONETOMANY and child is not None and self.post_update: </del><ins>+ if child is not None and self.post_update: </ins><span class="cx"> uowcommit.register_object(child, postupdate=True) </span><del>- if self.direction == MANYTOONE: - if self.post_update: - uowcommit.register_object(obj, postupdate=True) - else: - for child in childlist.deleted_items(): - if not self.cascade.delete_orphan: - self._synchronize(obj, child, None, True) </del><ins>+ for child in childlist.deleted_items(): + if not self.cascade.delete_orphan: + self._synchronize(obj, child, None, True) </ins><span class="cx"> </span><span class="cx"> def preprocess_dependencies(self, task, deplist, uowcommit, delete = False): </span><del>- """used before the flushes' topological sort to traverse through related objects and insure every - instance which will require save/update/delete is properly added to the UOWTransaction.""" </del><span class="cx"> #print self.mapper.table.name + " " + self.key + " " + repr(len(deplist)) + " process_dep isdelete " + repr(delete) + " direction " + repr(self.direction) </span><span class="cx"> </span><del>- # TODO: post_update instructions should be established in this step as well - # (and executed in the regular traversal) - if self.post_update: - return - - # TODO: this method is the product of splitting process_dependencies into two methods. - # cleanup is still required to hone the method down to its minimal amount of code. - - def getlist(obj, passive=True): - return self.get_object_dependencies(obj, uowcommit, passive) - - if self.direction == MANYTOMANY: - pass - elif self.direction == MANYTOONE and delete: - if self.cascade.delete_orphan: - for obj in deplist: - childlist = getlist(obj, False) - for child in childlist.deleted_items() + childlist.unchanged_items(): - if child is not None and childlist.hasparent(child) is False: - uowcommit.register_object(child, isdelete=True) - elif self.direction == ONETOMANY and delete: </del><ins>+ if delete: </ins><span class="cx"> # head object is being deleted, and we manage its list of child objects </span><span class="cx"> # the child objects have to have their foreign key to the parent set to NULL </span><del>- if self.cascade.delete_orphan and not self.post_update: </del><ins>+ if self.post_update: + # TODO: post_update instructions should be established in this step as well + # (and executed in the regular traversal) + pass + elif self.cascade.delete_orphan: </ins><span class="cx"> for obj in deplist: </span><del>- childlist = getlist(obj, False) </del><ins>+ childlist = self.get_object_dependencies(obj, uowcommit, passive=False) </ins><span class="cx"> for child in childlist.deleted_items(): </span><span class="cx"> if child is not None and childlist.hasparent(child) is False: </span><span class="cx"> uowcommit.register_object(child, isdelete=True) </span><span class="lines">@@ -284,48 +141,213 @@ </span><span class="cx"> uowcommit.register_object(child, isdelete=True) </span><span class="cx"> else: </span><span class="cx"> for obj in deplist: </span><del>- childlist = getlist(obj, False) </del><ins>+ childlist = self.get_object_dependencies(obj, uowcommit, passive=False) </ins><span class="cx"> for child in childlist.deleted_items(): </span><span class="cx"> if child is not None and childlist.hasparent(child) is False: </span><span class="cx"> uowcommit.register_object(child) </span><span class="cx"> for child in childlist.unchanged_items(): </span><span class="cx"> if child is not None: </span><span class="cx"> uowcommit.register_object(child) </span><del>- elif self.association is not None: - # TODO: clean up the association step in process_dependencies and move the - # appropriate sections of it to here - pass </del><span class="cx"> else: </span><span class="cx"> for obj in deplist: </span><del>- childlist = getlist(obj, passive=True) </del><ins>+ childlist = self.get_object_dependencies(obj, uowcommit, passive=True) </ins><span class="cx"> if childlist is not None: </span><span class="cx"> for child in childlist.added_items(): </span><del>- if self.direction == ONETOMANY and child is not None: </del><ins>+ if child is not None: </ins><span class="cx"> uowcommit.register_object(child) </span><del>- if self.direction == MANYTOONE: - uowcommit.register_object(obj) - else: - for child in childlist.deleted_items(): - if not self.cascade.delete_orphan: - uowcommit.register_object(child, isdelete=False) - elif childlist.hasparent(child) is False: </del><ins>+ for child in childlist.deleted_items(): + if not self.cascade.delete_orphan: + uowcommit.register_object(child, isdelete=False) + elif childlist.hasparent(child) is False: + uowcommit.register_object(child, isdelete=True) + + def _synchronize(self, obj, child, associationrow, clearkeys): + source = obj + dest = child + if dest is None: + return + self.syncrules.execute(source, dest, obj, child, clearkeys) + +class ManyToOneDP(DependencyProcessor): + def register_dependencies(self, uowcommit): + if self.post_update: + stub = MapperStub(self.mapper) + uowcommit.register_dependency(self.mapper, stub) + uowcommit.register_dependency(self.parent, stub) + uowcommit.register_processor(stub, self, self.parent) + else: + uowcommit.register_dependency(self.mapper, self.parent) + uowcommit.register_processor(self.mapper, self, self.parent) + def process_dependencies(self, task, deplist, uowcommit, delete = False): + #print self.mapper.table.name + " " + self.key + " " + repr(len(deplist)) + " process_dep isdelete " + repr(delete) + " direction " + repr(self.direction) + if delete: + if self.post_update and not self.cascade.delete_orphan: + # post_update means we have to update our row to not reference the child object + # before we can DELETE the row + for obj in deplist: + self._synchronize(obj, None, None, True) + uowcommit.register_object(obj, postupdate=True) + else: + for obj in deplist: + childlist = self.get_object_dependencies(obj, uowcommit, passive=True) + if childlist is not None: + for child in childlist.added_items(): + self._synchronize(obj, child, None, False) + if self.post_update: + uowcommit.register_object(obj, postupdate=True) + + def preprocess_dependencies(self, task, deplist, uowcommit, delete = False): + #print self.mapper.table.name + " " + self.key + " " + repr(len(deplist)) + " process_dep isdelete " + repr(delete) + " direction " + repr(self.direction) + # TODO: post_update instructions should be established in this step as well + # (and executed in the regular traversal) + if self.post_update: + return + if delete: + if self.cascade.delete_orphan: + for obj in deplist: + childlist = self.get_object_dependencies(obj, uowcommit, passive=False) + for child in childlist.deleted_items() + childlist.unchanged_items(): + if child is not None and childlist.hasparent(child) is False: </ins><span class="cx"> uowcommit.register_object(child, isdelete=True) </span><ins>+ else: + for obj in deplist: + childlist = self.get_object_dependencies(obj, uowcommit, passive=True) + uowcommit.register_object(obj) + + def _synchronize(self, obj, child, associationrow, clearkeys): + source = child + dest = obj + if dest is None: + return + self.syncrules.execute(source, dest, obj, child, clearkeys) </ins><span class="cx"> </span><del>- </del><ins>+class ManyToManyDP(DependencyProcessor): + def register_dependencies(self, uowcommit): + # many-to-many. create a "Stub" mapper to represent the + # "middle table" in the relationship. This stub mapper doesnt save + # or delete any objects, but just marks a dependency on the two + # related mappers. its dependency processor then populates the + # association table. + + if self.is_backref: + # if we are the "backref" half of a two-way backref + # relationship, let the other mapper handle inserting the rows + return + stub = MapperStub(self.mapper) + uowcommit.register_dependency(self.parent, stub) + uowcommit.register_dependency(self.mapper, stub) + uowcommit.register_processor(stub, self, self.parent) + + def process_dependencies(self, task, deplist, uowcommit, delete = False): + #print self.mapper.table.name + " " + self.key + " " + repr(len(deplist)) + " process_dep isdelete " + repr(delete) + " direction " + repr(self.direction) + connection = uowcommit.transaction.connection(self.mapper) + secondary_delete = [] + secondary_insert = [] + if delete: + for obj in deplist: + childlist = self.get_object_dependencies(obj, uowcommit, passive=False) + for child in childlist.deleted_items() + childlist.unchanged_items(): + associationrow = {} + self._synchronize(obj, child, associationrow, False) + secondary_delete.append(associationrow) + else: + for obj in deplist: + childlist = self.get_object_dependencies(obj, uowcommit) + if childlist is None: continue + for child in childlist.added_items(): + associationrow = {} + self._synchronize(obj, child, associationrow, False) + secondary_insert.append(associationrow) + for child in childlist.deleted_items(): + associationrow = {} + self._synchronize(obj, child, associationrow, False) + secondary_delete.append(associationrow) + if len(secondary_delete): + # TODO: precompile the delete/insert queries and store them as instance variables + # on the PropertyLoader + statement = self.secondary.delete(sql.and_(*[c == sql.bindparam(c.key) for c in self.secondary.c])) + connection.execute(statement, secondary_delete) + if len(secondary_insert): + statement = self.secondary.insert() + connection.execute(statement, secondary_insert) + + def preprocess_dependencies(self, task, deplist, uowcommit, delete = False): + pass </ins><span class="cx"> def _synchronize(self, obj, child, associationrow, clearkeys): </span><del>- """called during a flush to synchronize primary key identifier values between a parent/child object, as well as - to an associationrow in the case of many-to-many.""" - if self.direction == ONETOMANY: - source = obj - dest = child - elif self.direction == MANYTOONE: - source = child - dest = obj - elif self.direction == MANYTOMANY: - dest = associationrow - source = None - </del><ins>+ dest = associationrow + source = None </ins><span class="cx"> if dest is None: </span><span class="cx"> return </span><ins>+ self.syncrules.execute(source, dest, obj, child, clearkeys) </ins><span class="cx"> </span><del>- self.syncrules.execute(source, dest, obj, child, clearkeys) </del><ins>+class AssociationDP(OneToManyDP): + def register_dependencies(self, uowcommit): + # association object. our mapper should be dependent on both + # the parent mapper and the association object mapper. + # this is where we put the "stub" as a marker, so we get + # association/parent->stub->self, then we process the child + # elments after the 'stub' save, which is before our own + # mapper's save. + stub = MapperStub(self.association) + uowcommit.register_dependency(self.parent, stub) + uowcommit.register_dependency(self.association, stub) + uowcommit.register_dependency(stub, self.mapper) + uowcommit.register_processor(stub, self, self.parent) + def process_dependencies(self, task, deplist, uowcommit, delete = False): + #print self.mapper.table.name + " " + self.key + " " + repr(len(deplist)) + " process_dep isdelete " + repr(delete) + " direction " + repr(self.direction) + # manage association objects. + for obj in deplist: + childlist = self.get_object_dependencies(obj, uowcommit, passive=True) + if childlist is None: continue + + #print "DIRECTION", self.direction + d = {} + for child in childlist: + self._synchronize(obj, child, None, False) + key = self.mapper.instance_key(child) + #print "SYNCHRONIZED", child, "INSTANCE KEY", key + d[key] = child + uowcommit.unregister_object(child) + + for child in childlist.added_items(): + uowcommit.register_object(child) + key = self.mapper.instance_key(child) + #print "ADDED, INSTANCE KEY", key + d[key] = child + + for child in childlist.unchanged_items(): + key = self.mapper.instance_key(child) + o = d[key] + o._instance_key= key + + for child in childlist.deleted_items(): + key = self.mapper.instance_key(child) + #print "DELETED, INSTANCE KEY", key + if d.has_key(key): + o = d[key] + o._instance_key = key + uowcommit.unregister_object(child) + else: + #print "DELETE ASSOC OBJ", repr(child) + uowcommit.register_object(child, isdelete=True) + def preprocess_dependencies(self, task, deplist, uowcommit, delete = False): + # TODO: clean up the association step in process_dependencies and move the + # appropriate sections of it to here + pass + + +class MapperStub(object): + """poses as a Mapper representing the association table in a many-to-many + join, when performing a flush(). + + The Task objects in the objectstore module treat it just like + any other Mapper, but in fact it only serves as a "dependency" placeholder + for the many-to-many update task.""" + def __init__(self, mapper): + self.mapper = mapper + def save_obj(self, *args, **kwargs): + pass + def delete_obj(self, *args, **kwargs): + pass + def _primary_mapper(self): + return self </ins></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyormpropertiespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/properties.py (1492 => 1493)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/properties.py 2006-05-23 15:40:29 UTC (rev 1492) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/properties.py 2006-05-23 23:57:29 UTC (rev 1493) </span><span class="lines">@@ -228,7 +228,7 @@ </span><span class="cx"> self.uselist = True </span><span class="cx"> </span><span class="cx"> self._compile_synchronizers() </span><del>- self._dependency_processor = dependency.DependencyProcessor(self.key, self.syncrules, self.cascade, secondary=self.secondary, association=self.association, is_backref=self.is_backref, post_update=self.post_update) </del><ins>+ self._dependency_processor = dependency.create_dependency_processor(self.key, self.syncrules, self.cascade, secondary=self.secondary, association=self.association, is_backref=self.is_backref, post_update=self.post_update) </ins><span class="cx"> </span><span class="cx"> # primary property handler, set up class attributes </span><span class="cx"> if self.is_primary(): </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyormunitofworkpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/unitofwork.py (1492 => 1493)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/unitofwork.py 2006-05-23 15:40:29 UTC (rev 1492) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/unitofwork.py 2006-05-23 23:57:29 UTC (rev 1493) </span><span class="lines">@@ -269,7 +269,7 @@ </span><span class="cx"> self.dependencies = {} </span><span class="cx"> self.tasks = {} </span><span class="cx"> self.__modified = False </span><del>- self._is_executing = False </del><ins>+ self.__is_executing = False </ins><span class="cx"> </span><span class="cx"> def register_object(self, obj, isdelete = False, listonly = False, postupdate=False, **kwargs): </span><span class="cx"> """adds an object to this UOWTransaction to be updated in the database. </span><span class="lines">@@ -281,6 +281,7 @@ </span><span class="cx"> save/delete operation on the object itself, unless an additional save/delete </span><span class="cx"> registration is entered for the object.""" </span><span class="cx"> #print "REGISTER", repr(obj), repr(getattr(obj, '_instance_key', None)), str(isdelete), str(listonly) </span><ins>+ </ins><span class="cx"> # things can get really confusing if theres duplicate instances floating around, </span><span class="cx"> # so make sure everything is OK </span><span class="cx"> self.uow._validate_obj(obj) </span><span class="lines">@@ -288,12 +289,12 @@ </span><span class="cx"> mapper = object_mapper(obj) </span><span class="cx"> self.mappers.append(mapper) </span><span class="cx"> task = self.get_task_by_mapper(mapper) </span><del>- </del><ins>+ </ins><span class="cx"> if postupdate: </span><span class="cx"> mod = task.append_postupdate(obj) </span><del>- self.__modified = self.__modified or mod </del><ins>+ if mod: self._mark_modified() </ins><span class="cx"> return </span><del>- </del><ins>+ </ins><span class="cx"> # for a cyclical task, things need to be sorted out already, </span><span class="cx"> # so this object should have already been added to the appropriate sub-task </span><span class="cx"> # can put an assertion here to make sure.... </span><span class="lines">@@ -301,12 +302,18 @@ </span><span class="cx"> return </span><span class="cx"> </span><span class="cx"> mod = task.append(obj, listonly, isdelete=isdelete, **kwargs) </span><del>- self.__modified = self.__modified or mod </del><ins>+ if mod: self._mark_modified() </ins><span class="cx"> </span><span class="cx"> def unregister_object(self, obj): </span><span class="cx"> mapper = object_mapper(obj) </span><span class="cx"> task = self.get_task_by_mapper(mapper) </span><del>- task.delete(obj) </del><ins>+ if obj in task.objects: + task.delete(obj) + self._mark_modified() + + def _mark_modified(self): + #if self.__is_executing: + # raise "test assertion failed" </ins><span class="cx"> self.__modified = True </span><span class="cx"> </span><span class="cx"> def get_task_by_mapper(self, mapper): </span><span class="lines">@@ -325,9 +332,9 @@ </span><span class="cx"> one mapper being dependent on the objects handled by another.""" </span><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><del>- self.__modified = True </del><ins>+ self._mark_modified() </ins><span class="cx"> </span><del>- def register_processor(self, mapper, processor, mapperfrom, isdeletefrom): </del><ins>+ def register_processor(self, mapper, processor, mapperfrom): </ins><span class="cx"> """called by mapper.PropertyLoader to register itself as a "processor", which </span><span class="cx"> will be associated with a particular UOWTask, and be given a list of "dependent" </span><span class="cx"> objects corresponding to another UOWTask to be processed, either after that secondary </span><span class="lines">@@ -335,23 +342,23 @@ </span><span class="cx"> # when the task from "mapper" executes, take the objects from the task corresponding </span><span class="cx"> # to "mapperfrom"'s list of save/delete objects, and send them to "processor" </span><span class="cx"> # for dependency processing </span><del>- #print "registerprocessor", str(mapper), repr(processor.key), str(mapperfrom), repr(isdeletefrom) </del><ins>+ #print "registerprocessor", str(mapper), repr(processor.key), str(mapperfrom) </ins><span class="cx"> </span><span class="cx"> # correct for primary mapper (the mapper offcially associated with the class) </span><span class="cx"> mapper = mapper._primary_mapper() </span><span class="cx"> mapperfrom = mapperfrom._primary_mapper() </span><span class="cx"> task = self.get_task_by_mapper(mapper) </span><span class="cx"> targettask = self.get_task_by_mapper(mapperfrom) </span><del>- up = UOWDependencyProcessor(processor, targettask, isdeletefrom) </del><ins>+ up = UOWDependencyProcessor(processor, targettask) </ins><span class="cx"> task.dependencies.append(up) </span><span class="cx"> up.preexecute(self) </span><del>- self.__modified = True </del><ins>+ self._mark_modified() </ins><span class="cx"> </span><span class="cx"> def execute(self, echo=False): </span><span class="cx"> for task in self.tasks.values(): </span><span class="cx"> task.mapper.register_dependencies(self) </span><span class="cx"> </span><del>- self._is_executing = True </del><ins>+ self.__is_executing = True </ins><span class="cx"> </span><span class="cx"> head = self._sort_dependencies() </span><span class="cx"> self.__modified = False </span><span class="lines">@@ -365,10 +372,7 @@ </span><span class="cx"> #if self.__modified and head is not None: </span><span class="cx"> # raise "Assertion failed ! new pre-execute dependency step should eliminate post-execute changes (except post_update stuff)." </span><span class="cx"> if LOG or echo: </span><del>- if self.__modified and head is not None: - print "\nAfter Execute:\n" + head.dump() - else: - print "\nExecute complete (no post-exec changes)\n" </del><ins>+ print "\nExecute complete\n" </ins><span class="cx"> </span><span class="cx"> def post_exec(self): </span><span class="cx"> """after an execute/flush is completed, all of the objects and lists that have </span><span class="lines">@@ -427,22 +431,19 @@ </span><span class="cx"> """in between the saving and deleting of objects, process "dependent" data, such as filling in </span><span class="cx"> a foreign key on a child item from a new primary key, or deleting association rows before a </span><span class="cx"> delete. This object acts as a proxy to a DependencyProcessor.""" </span><del>- def __init__(self, processor, targettask, isdeletefrom): </del><ins>+ def __init__(self, processor, targettask): </ins><span class="cx"> self.processor = processor </span><span class="cx"> self.targettask = targettask </span><del>- self.isdeletefrom = isdeletefrom </del><span class="cx"> </span><span class="cx"> def preexecute(self, trans): </span><del>- if not self.isdeletefrom: - self.processor.preprocess_dependencies(self.targettask, [elem.obj for elem in self.targettask.tosave_elements() if elem.obj is not None], trans, delete=self.isdeletefrom) - else: - self.processor.preprocess_dependencies(self.targettask, [elem.obj for elem in self.targettask.todelete_elements() if elem.obj is not None], trans, delete=self.isdeletefrom) </del><ins>+ self.processor.preprocess_dependencies(self.targettask, [elem.obj for elem in self.targettask.tosave_elements if elem.obj is not None], trans, delete=False) + self.processor.preprocess_dependencies(self.targettask, [elem.obj for elem in self.targettask.todelete_elements if elem.obj is not None], trans, delete=True) </ins><span class="cx"> </span><del>- def execute(self, trans): - if not self.isdeletefrom: - self.processor.process_dependencies(self.targettask, [elem.obj for elem in self.targettask.tosave_elements() if elem.obj is not None], trans, delete=self.isdeletefrom) </del><ins>+ def execute(self, trans, delete): + if not delete: + self.processor.process_dependencies(self.targettask, [elem.obj for elem in self.targettask.tosave_elements if elem.obj is not None], trans, delete=False) </ins><span class="cx"> else: </span><del>- self.processor.process_dependencies(self.targettask, [elem.obj for elem in self.targettask.todelete_elements() if elem.obj is not None], trans, delete=self.isdeletefrom) </del><ins>+ self.processor.process_dependencies(self.targettask, [elem.obj for elem in self.targettask.todelete_elements if elem.obj is not None], trans, delete=True) </ins><span class="cx"> </span><span class="cx"> def get_object_dependencies(self, obj, trans, passive): </span><span class="cx"> return self.processor.get_object_dependencies(obj, trans, passive=passive) </span><span class="lines">@@ -451,7 +452,7 @@ </span><span class="cx"> return self.processor.whose_dependent_on_who(obj, o) </span><span class="cx"> </span><span class="cx"> def branch(self, task): </span><del>- return UOWDependencyProcessor(self.processor, task, self.isdeletefrom) </del><ins>+ return UOWDependencyProcessor(self.processor, task) </ins><span class="cx"> </span><span class="cx"> class UOWTask(object): </span><span class="cx"> def __init__(self, uowtransaction, mapper): </span><span class="lines">@@ -508,41 +509,29 @@ </span><span class="cx"> self.circular.execute(trans) </span><span class="cx"> return </span><span class="cx"> </span><del>- self.mapper.save_obj(self.tosave_objects(), trans) - for dep in self.cyclical_save_dependencies(): - dep.execute(trans) - for element in self.tosave_elements(): </del><ins>+ self.mapper.save_obj(self.tosave_objects, trans) + for dep in self.cyclical_dependencies: + dep.execute(trans, False) + for element in self.tosave_elements: </ins><span class="cx"> for task in element.childtasks: </span><span class="cx"> task.execute(trans) </span><del>- for dep in self.save_dependencies(): - dep.execute(trans) - for dep in self.delete_dependencies(): - dep.execute(trans) - for dep in self.cyclical_delete_dependencies(): - dep.execute(trans) </del><ins>+ for dep in self.dependencies: + dep.execute(trans, False) + for dep in self.dependencies: + dep.execute(trans, True) + for dep in self.cyclical_dependencies: + dep.execute(trans, True) </ins><span class="cx"> for child in self.childtasks: </span><span class="cx"> child.execute(trans) </span><del>- for element in self.todelete_elements(): </del><ins>+ for element in self.todelete_elements: </ins><span class="cx"> for task in element.childtasks: </span><span class="cx"> task.execute(trans) </span><del>- self.mapper.delete_obj(self.todelete_objects(), trans) </del><ins>+ self.mapper.delete_obj(self.todelete_objects, trans) </ins><span class="cx"> </span><del>- def tosave_elements(self): - return [rec for rec in self.objects.values() if not rec.isdelete] - def todelete_elements(self): - return [rec for rec in self.objects.values() if rec.isdelete] - def tosave_objects(self): - return [rec.obj for rec in self.objects.values() if rec.obj is not None and not rec.listonly and rec.isdelete is False] - def todelete_objects(self): - return [rec.obj for rec in self.objects.values() if rec.obj is not None and not rec.listonly and rec.isdelete is True] - def save_dependencies(self): - return [dep for dep in self.dependencies if not dep.isdeletefrom] - def cyclical_save_dependencies(self): - return [dep for dep in self.cyclical_dependencies if not dep.isdeletefrom] - def delete_dependencies(self): - return [dep for dep in self.dependencies if dep.isdeletefrom] - def cyclical_delete_dependencies(self): - return [dep for dep in self.cyclical_dependencies if dep.isdeletefrom] </del><ins>+ tosave_elements = property(lambda self: [rec for rec in self.objects.values() if not rec.isdelete]) + todelete_elements = property(lambda self:[rec for rec in self.objects.values() if rec.isdelete]) + tosave_objects = property(lambda self:[rec.obj for rec in self.objects.values() if rec.obj is not None and not rec.listonly and rec.isdelete is False]) + todelete_objects = property(lambda self:[rec.obj for rec in self.objects.values() if rec.obj is not None and not rec.listonly and rec.isdelete is True]) </ins><span class="cx"> </span><span class="cx"> def _sort_circular_dependencies(self, trans, cycles): </span><span class="cx"> """for a single task, creates a hierarchical tree of "subtasks" which associate </span><span class="lines">@@ -605,21 +594,18 @@ </span><span class="cx"> #print "OBJ", repr(obj), "TASK", repr(task) </span><span class="cx"> </span><span class="cx"> for dep in deps_by_targettask.get(task, []): </span><del>- (processor, targettask, isdelete) = (dep.processor, dep.targettask, dep.isdeletefrom) - if taskelement.isdelete is not dep.isdeletefrom: </del><ins>+ # is this dependency involved in one of the cycles ? + cyclicaldep = dep.targettask in cycles and trans.get_task_by_mapper(dep.processor.mapper) in cycles + if not cyclicaldep: </ins><span class="cx"> continue </span><del>- #print "GETING LIST OFF PROC", processor.key, "OBJ", repr(obj) - - # traverse through the modified child items of each object. normally this - # is done via PropertyLoader in properties.py, but we need all the info - # up front here to do the object-level topological sort. </del><ins>+ + (processor, targettask) = (dep.processor, dep.targettask) + isdelete = taskelement.isdelete </ins><span class="cx"> </span><span class="cx"> # list of dependent objects from this object </span><span class="cx"> childlist = dep.get_object_dependencies(obj, trans, passive = True) </span><span class="cx"> # the task corresponding to the processor's objects </span><span class="cx"> childtask = trans.get_task_by_mapper(processor.mapper) </span><del>- # is this dependency involved in one of the cycles ? - cyclicaldep = dep.targettask in cycles and trans.get_task_by_mapper(dep.processor.mapper) in cycles </del><span class="cx"> </span><span class="cx"> if isdelete: </span><span class="cx"> childlist = childlist.unchanged_items() + childlist.deleted_items() </span><span class="lines">@@ -627,23 +613,19 @@ </span><span class="cx"> childlist = childlist.added_items() </span><span class="cx"> </span><span class="cx"> for o in childlist: </span><del>- if o is None: </del><ins>+ if o is None or o not in childtask.objects: </ins><span class="cx"> continue </span><del>- if not o in childtask.objects: - object_to_original_task[o] = childtask - if cyclicaldep: - # cyclical, so create an ordered pair for the dependency sort - whosdep = dep.whose_dependent_on_who(obj, o) - if whosdep is not None: - tuples.append(whosdep) - # create a UOWDependencyProcessor representing this pair of objects. - # append it to a UOWTask - if whosdep[0] is obj: - get_dependency_task(obj, dep).append(whosdep[0], isdelete=isdelete) - else: - get_dependency_task(obj, dep).append(whosdep[1], isdelete=isdelete) </del><ins>+ whosdep = dep.whose_dependent_on_who(obj, o) + if whosdep is not None: + tuples.append(whosdep) + # create a UOWDependencyProcessor representing this pair of objects. + # append it to a UOWTask + if whosdep[0] is obj: + get_dependency_task(obj, dep).append(whosdep[0], isdelete=isdelete) </ins><span class="cx"> else: </span><del>- get_dependency_task(obj, dep).append(obj, isdelete=isdelete) </del><ins>+ get_dependency_task(obj, dep).append(whosdep[1], isdelete=isdelete) + else: + get_dependency_task(obj, dep).append(obj, isdelete=isdelete) </ins><span class="cx"> </span><span class="cx"> head = DependencySorter(tuples, allobjects).sort() </span><span class="cx"> if head is None: </span><span class="lines">@@ -675,8 +657,8 @@ </span><span class="cx"> else: </span><span class="cx"> t.append(node.item, original_task.objects[node.item].listonly, isdelete=original_task.objects[node.item].isdelete) </span><span class="cx"> parenttask.append(None, listonly=False, isdelete=original_task.objects[node.item].isdelete, childtask=t) </span><del>- else: - parenttask.append(None, listonly=False, isdelete=original_task.objects[node.item].isdelete, childtask=t) </del><ins>+ #else: + # parenttask.append(None, listonly=False, isdelete=original_task.objects[node.item].isdelete, childtask=t) </ins><span class="cx"> if dependencies.has_key(node.item): </span><span class="cx"> for depprocessor, deptask in dependencies[node.item].iteritems(): </span><span class="cx"> if can_add_to_parent: </span><span class="lines">@@ -716,17 +698,15 @@ </span><span class="cx"> buf.write(text) </span><span class="cx"> headers[text] = True </span><span class="cx"> </span><del>- def _dump_processor(proc): - if proc.isdeletefrom: </del><ins>+ def _dump_processor(proc, deletes): + if deletes: </ins><span class="cx"> val = [t for t in proc.targettask.objects.values() if t.isdelete] </span><span class="cx"> else: </span><span class="cx"> val = [t for t in proc.targettask.objects.values() if not t.isdelete] </span><span class="cx"> </span><span class="cx"> buf.write(_indent() + " |- %s attribute on %s (UOWDependencyProcessor(%d) processing %s)\n" % ( </span><span class="cx"> repr(proc.processor.key), </span><del>- (proc.isdeletefrom and - "%s's to be deleted" % _repr_task_class(proc.targettask) - or "saved %s's" % _repr_task_class(proc.targettask)), </del><ins>+ ("%s's to be %s" % (_repr_task_class(proc.targettask), deletes and "deleted" or "saved")), </ins><span class="cx"> id(proc), </span><span class="cx"> _repr_task(proc.targettask)) </span><span class="cx"> ) </span><span class="lines">@@ -778,39 +758,39 @@ </span><span class="cx"> buf.write(i + " " + _repr_task(self)) </span><span class="cx"> </span><span class="cx"> buf.write("\n") </span><del>- for rec in self.tosave_elements(): </del><ins>+ for rec in self.tosave_elements: </ins><span class="cx"> if rec.listonly: </span><span class="cx"> continue </span><span class="cx"> header(buf, _indent() + " |- Save elements\n") </span><span class="cx"> buf.write(_indent() + " |- " + _repr_task_element(rec) + "\n") </span><del>- for dep in self.cyclical_save_dependencies(): </del><ins>+ for dep in self.cyclical_dependencies: </ins><span class="cx"> header(buf, _indent() + " |- Cyclical Save dependencies\n") </span><del>- _dump_processor(dep) - for element in self.tosave_elements(): </del><ins>+ _dump_processor(dep, False) + for element in self.tosave_elements: </ins><span class="cx"> for task in element.childtasks: </span><span class="cx"> header(buf, _indent() + " |- Save subelements of UOWTaskElement(%s)\n" % id(element)) </span><span class="cx"> task._dump(buf, indent + 1) </span><del>- for dep in self.save_dependencies(): </del><ins>+ for dep in self.dependencies: </ins><span class="cx"> header(buf, _indent() + " |- Save dependencies\n") </span><del>- _dump_processor(dep) - for dep in self.delete_dependencies(): </del><ins>+ _dump_processor(dep, False) + for dep in self.dependencies: </ins><span class="cx"> header(buf, _indent() + " |- Delete dependencies\n") </span><del>- _dump_processor(dep) - for dep in self.cyclical_delete_dependencies(): </del><ins>+ _dump_processor(dep, True) + for dep in self.cyclical_dependencies: </ins><span class="cx"> header(buf, _indent() + " |- Cyclical Delete dependencies\n") </span><del>- _dump_processor(dep) </del><ins>+ _dump_processor(dep, True) </ins><span class="cx"> for child in self.childtasks: </span><span class="cx"> header(buf, _indent() + " |- Child tasks\n") </span><span class="cx"> child._dump(buf, indent + 1) </span><span class="cx"> # for obj in self.postupdate: </span><span class="cx"> # header(buf, _indent() + " |- Post Update objects\n") </span><span class="cx"> # buf.write(_repr(obj) + "\n") </span><del>- ... [truncated message content] |
<!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>[1492] sqlalchemy/branches/schema/lib/sqlalchemy/orm: single table inheritance fix, if local_table is None it gets set to that of the inheriting mapper</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1492</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-05-23 10:40:29 -0500 (Tue, 23 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>single table inheritance fix, if local_table is None it gets set to that of the inheriting mapper</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemaexamplespolymorphsinglepy">sqlalchemy/branches/schema/examples/polymorph/single.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyormmapperpy">sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschemaexamplespolymorphsinglepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/examples/polymorph/single.py (1491 => 1492)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/examples/polymorph/single.py 2006-05-23 15:02:00 UTC (rev 1491) +++ sqlalchemy/branches/schema/examples/polymorph/single.py 2006-05-23 15:40:29 UTC (rev 1492) </span><span class="lines">@@ -12,6 +12,7 @@ </span><span class="cx"> Column('company_id', Integer, ForeignKey('companies.company_id')), </span><span class="cx"> Column('name', String(50)), </span><span class="cx"> Column('type', String(20)), </span><ins>+ Column('status', String(20)), </ins><span class="cx"> Column('engineer_name', String(50)), </span><span class="cx"> Column('primary_language', String(50)), </span><span class="cx"> Column('manager_name', String(50)) </span><span class="lines">@@ -39,8 +40,8 @@ </span><span class="cx"> return "Company %s" % self.name </span><span class="cx"> </span><span class="cx"> person_mapper = mapper(Person, employees_table, polymorphic_on=employees_table.c.type, polymorphic_identity='person') </span><del>-manager_mapper = mapper(Manager, inherits=employee_mapper, polymorphic_identity='manager') -engineer_mapper = mapper(Engineer, inherits=employee_mapper, polymorphic_identity='engineer') </del><ins>+manager_mapper = mapper(Manager, inherits=person_mapper, polymorphic_identity='manager') +engineer_mapper = mapper(Engineer, inherits=person_mapper, polymorphic_identity='engineer') </ins><span class="cx"> </span><span class="cx"> </span><span class="cx"> </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyormmapperpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py (1491 => 1492)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py 2006-05-23 15:02:00 UTC (rev 1491) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py 2006-05-23 15:40:29 UTC (rev 1492) </span><span class="lines">@@ -127,6 +127,8 @@ </span><span class="cx"> if self.class_.__mro__[1] != inherits.class_: </span><span class="cx"> raise exceptions.ArgumentError("Class '%s' does not inherit from '%s'" % (self.class_.__name__, inherits.class_.__name__)) </span><span class="cx"> # inherit_condition is optional. </span><ins>+ if local_table is None: + self.local_table = local_table = inherits.local_table </ins><span class="cx"> if not local_table is inherits.local_table: </span><span class="cx"> if concrete: </span><span class="cx"> self._synchronizer= None </span><span class="lines">@@ -147,6 +149,7 @@ </span><span class="cx"> self._synchronizer.compile(self.mapped_table.onclause, util.HashSet([inherits.local_table]), sqlutil.TableFinder(self.local_table)) </span><span class="cx"> else: </span><span class="cx"> self._synchronizer = None </span><ins>+ self.mapped_table = self.local_table </ins><span class="cx"> self.inherits = inherits </span><span class="cx"> if polymorphic_identity is not None: </span><span class="cx"> inherits.add_polymorphic_mapping(polymorphic_identity, self) </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-05-23 15:02:16
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head><style type="text/css"><!-- #msg dl { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; } #msg dt { float: left; width: 6em; font-weight: bold; } #msg dt:after { content:':';} #msg dl, #msg dt, #msg ul, #msg li { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; } #msg dl a { font-weight: bold} #msg dl a:link { color:#fc3; } #msg dl a:active { color:#ff0; } #msg dl a:visited { color:#cc6; } h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; } #msg pre { overflow: auto; background: #ffc; border: 1px #fc0 solid; padding: 6px; } #msg ul, pre { overflow: auto; } #patch { width: 100%; } #patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;} #patch .propset h4, #patch .binary h4 {margin:0;} #patch pre {padding:0;line-height:1.2em;margin:0;} #patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;} #patch .propset .diff, #patch .binary .diff {padding:10px 0;} #patch span {display:block;padding:0 10px;} #patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;} #patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;} #patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;} #patch .lines, .info {color:#888;background:#fff;} --></style> <title>[1491] sqlalchemy/branches/schema/test: merged index naming fix</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1491</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-05-23 10:02:00 -0500 (Tue, 23 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>merged index naming fix</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemalibsqlalchemyschemapy">sqlalchemy/branches/schema/lib/sqlalchemy/schema.py</a></li> <li><a href="#sqlalchemybranchesschematestindexespy">sqlalchemy/branches/schema/test/indexes.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschemalibsqlalchemyschemapy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/schema.py (1490 => 1491)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/schema.py 2006-05-23 14:59:32 UTC (rev 1490) +++ sqlalchemy/branches/schema/lib/sqlalchemy/schema.py 2006-05-23 15:02:00 UTC (rev 1491) </span><span class="lines">@@ -191,12 +191,12 @@ </span><span class="cx"> raise ValueError("index and unique may not both be specified") </span><span class="cx"> if index: </span><span class="cx"> if index is True: </span><del>- name = 'ix_%s' % column.name </del><ins>+ name = 'ix_%s' % column._label </ins><span class="cx"> else: </span><span class="cx"> name = index </span><span class="cx"> elif unique: </span><span class="cx"> if unique is True: </span><del>- name = 'ux_%s' % column.name </del><ins>+ name = 'ux_%s' % column._label </ins><span class="cx"> else: </span><span class="cx"> name = unique </span><span class="cx"> # find this index in self.indexes </span></span></pre></div> <a id="sqlalchemybranchesschematestindexespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/test/indexes.py (1490 => 1491)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/test/indexes.py 2006-05-23 14:59:32 UTC (rev 1490) +++ sqlalchemy/branches/schema/test/indexes.py 2006-05-23 15:02:00 UTC (rev 1491) </span><span class="lines">@@ -79,8 +79,8 @@ </span><span class="cx"> Column('winner', String(30), index='idx_winners')) </span><span class="cx"> </span><span class="cx"> index_names = [ ix.name for ix in events.indexes ] </span><del>- assert 'ux_name' in index_names - assert 'ix_location' in index_names </del><ins>+ assert 'ux_events_name' in index_names + assert 'ix_events_location' in index_names </ins><span class="cx"> assert 'sport_announcer' in index_names </span><span class="cx"> assert 'idx_winners' in index_names </span><span class="cx"> assert len(index_names) == 4 </span><span class="lines">@@ -95,9 +95,9 @@ </span><span class="cx"> </span><span class="cx"> assert capt[0].strip().startswith('CREATE TABLE events') </span><span class="cx"> assert capt[3].strip() == \ </span><del>- 'CREATE UNIQUE INDEX ux_name ON events (name)' </del><ins>+ 'CREATE UNIQUE INDEX ux_events_name ON events (name)' </ins><span class="cx"> assert capt[6].strip() == \ </span><del>- 'CREATE INDEX ix_location ON events (location)' </del><ins>+ 'CREATE INDEX ix_events_location ON events (location)' </ins><span class="cx"> assert capt[9].strip() == \ </span><span class="cx"> 'CREATE UNIQUE INDEX sport_announcer ON events (sport, announcer)' </span><span class="cx"> assert capt[12].strip() == \ </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-05-23 14:59:43
|
<!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>[1490] sqlalchemy/trunk: anonymous indexes use column._label to avoid name collisions</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1490</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-05-23 09:59:32 -0500 (Tue, 23 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>anonymous indexes use column._label to avoid name collisions</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunkCHANGES">sqlalchemy/trunk/CHANGES</a></li> <li><a href="#sqlalchemytrunklibsqlalchemyschemapy">sqlalchemy/trunk/lib/sqlalchemy/schema.py</a></li> <li><a href="#sqlalchemytrunktestindexespy">sqlalchemy/trunk/test/indexes.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunkCHANGES"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/CHANGES (1489 => 1490)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/CHANGES 2006-05-23 14:59:11 UTC (rev 1489) +++ sqlalchemy/trunk/CHANGES 2006-05-23 14:59:32 UTC (rev 1490) </span><span class="lines">@@ -1,3 +1,6 @@ </span><ins>+next +- anonymous indexes (via Column(unique=True) etc) use column._label for naming +to avoid collisions </ins><span class="cx"> 0.1.7 </span><span class="cx"> - some fixes to topological sort algorithm </span><span class="cx"> - added DISTINCT ON support to Postgres (just supply distinct=[col1,col2..]) </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemyschemapy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/schema.py (1489 => 1490)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/schema.py 2006-05-23 14:59:11 UTC (rev 1489) +++ sqlalchemy/trunk/lib/sqlalchemy/schema.py 2006-05-23 14:59:32 UTC (rev 1490) </span><span class="lines">@@ -208,12 +208,12 @@ </span><span class="cx"> raise ValueError("index and unique may not both be specified") </span><span class="cx"> if index: </span><span class="cx"> if index is True: </span><del>- name = 'ix_%s' % column.name </del><ins>+ name = 'ix_%s' % column._label </ins><span class="cx"> else: </span><span class="cx"> name = index </span><span class="cx"> elif unique: </span><span class="cx"> if unique is True: </span><del>- name = 'ux_%s' % column.name </del><ins>+ name = 'ux_%s' % column._label </ins><span class="cx"> else: </span><span class="cx"> name = unique </span><span class="cx"> # find this index in self.indexes </span></span></pre></div> <a id="sqlalchemytrunktestindexespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/test/indexes.py (1489 => 1490)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/test/indexes.py 2006-05-23 14:59:11 UTC (rev 1489) +++ sqlalchemy/trunk/test/indexes.py 2006-05-23 14:59:32 UTC (rev 1490) </span><span class="lines">@@ -87,8 +87,8 @@ </span><span class="cx"> Column('winner', String(30), index='idx_winners')) </span><span class="cx"> </span><span class="cx"> index_names = [ ix.name for ix in events.indexes ] </span><del>- assert 'ux_name' in index_names - assert 'ix_location' in index_names </del><ins>+ assert 'ux_events_name' in index_names + assert 'ix_events_location' in index_names </ins><span class="cx"> assert 'sport_announcer' in index_names </span><span class="cx"> assert 'idx_winners' in index_names </span><span class="cx"> assert len(index_names) == 4 </span><span class="lines">@@ -104,9 +104,9 @@ </span><span class="cx"> </span><span class="cx"> assert capt[0].strip().startswith('CREATE TABLE events') </span><span class="cx"> assert capt[2].strip() == \ </span><del>- 'CREATE UNIQUE INDEX ux_name ON events (name)' </del><ins>+ 'CREATE UNIQUE INDEX ux_events_name ON events (name)' </ins><span class="cx"> assert capt[4].strip() == \ </span><del>- 'CREATE INDEX ix_location ON events (location)' </del><ins>+ 'CREATE INDEX ix_events_location ON events (location)' </ins><span class="cx"> assert capt[6].strip() == \ </span><span class="cx"> 'CREATE UNIQUE INDEX sport_announcer ON events (sport, announcer)' </span><span class="cx"> assert capt[8].strip() == \ </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-05-23 14:59:25
|
<!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>[1489] sqlalchemy/trunk/test/selectable.py: hypothetical (failing) test for primary key selection of joins</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1489</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-05-23 09:59:11 -0500 (Tue, 23 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>hypothetical (failing) test for primary key selection of joins</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunktestselectablepy">sqlalchemy/trunk/test/selectable.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunktestselectablepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/test/selectable.py (1488 => 1489)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/test/selectable.py 2006-05-23 01:03:34 UTC (rev 1488) +++ sqlalchemy/trunk/test/selectable.py 2006-05-23 14:59:11 UTC (rev 1489) </span><span class="lines">@@ -25,6 +25,13 @@ </span><span class="cx"> redefine=True </span><span class="cx"> ) </span><span class="cx"> </span><ins>+table3 = Table('table3', db, + Column('col1', Integer, ForeignKey('table1.col1'), primary_key=True), + Column('col2', Integer), + Column('col3', String(20)), + redefine=True + ) + </ins><span class="cx"> class SelectableTest(testbase.AssertMixin): </span><span class="cx"> def testtablealias(self): </span><span class="cx"> a = table.alias('a') </span><span class="lines">@@ -36,6 +43,17 @@ </span><span class="cx"> print str(j) </span><span class="cx"> self.assert_(criterion.compare(j.onclause)) </span><span class="cx"> </span><ins>+ def testjoinpks(self): + a = join(table, table3) + b = join(table, table3, table.c.col1==table3.c.col2) + c = join(table, table3, table.c.col2==table3.c.col2) + d = join(table, table3, table.c.col2==table3.c.col1) + + self.assert_(a.primary_key==[table.c.col1]) + self.assert_(b.primary_key==[table.c.col1, table3.c.col1]) + self.assert_(c.primary_key==[table.c.col1, table3.c.col1]) + self.assert_(d.primary_key==[table.c.col1, table3.c.col1]) + </ins><span class="cx"> def testjoin(self): </span><span class="cx"> a = join(table, table2) </span><span class="cx"> print str(a.select(use_labels=True)) </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-05-23 01:03:54
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head><style type="text/css"><!-- #msg dl { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; } #msg dt { float: left; width: 6em; font-weight: bold; } #msg dt:after { content:':';} #msg dl, #msg dt, #msg ul, #msg li { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; } #msg dl a { font-weight: bold} #msg dl a:link { color:#fc3; } #msg dl a:active { color:#ff0; } #msg dl a:visited { color:#cc6; } h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; } #msg pre { overflow: auto; background: #ffc; border: 1px #fc0 solid; padding: 6px; } #msg ul, pre { overflow: auto; } #patch { width: 100%; } #patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;} #patch .propset h4, #patch .binary h4 {margin:0;} #patch pre {padding:0;line-height:1.2em;margin:0;} #patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;} #patch .propset .diff, #patch .binary .diff {padding:10px 0;} #patch span {display:block;padding:0 10px;} #patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;} #patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;} #patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;} #patch .lines, .info {color:#888;background:#fff;} --></style> <title>[1488] sqlalchemy/trunk/lib/sqlalchemy/databases/firebird.py: Implemented the changes from ticket 94</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1488</dd> <dt>Author</dt> <dd>jralston</dd> <dt>Date</dt> <dd>2006-05-22 20:03:34 -0500 (Mon, 22 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>Implemented the changes from ticket 94</pre> <h3>Modified 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="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/databases/firebird.py (1487 => 1488)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/databases/firebird.py 2006-05-22 19:34:44 UTC (rev 1487) +++ sqlalchemy/trunk/lib/sqlalchemy/databases/firebird.py 2006-05-23 01:03:34 UTC (rev 1488) </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"> </span><del>-import sys, StringIO, string </del><ins>+import sys, StringIO, string, datetime </ins><span class="cx"> </span><span class="cx"> import sqlalchemy.sql as sql </span><span class="cx"> import sqlalchemy.schema as schema </span><span class="lines">@@ -30,6 +30,16 @@ </span><span class="cx"> class FBDateTime(sqltypes.DateTime): </span><span class="cx"> def get_col_spec(self): </span><span class="cx"> return "DATE" </span><ins>+ def convert_bind_param(self, value, engine): + if value is not None: + if isinstance(value, datetime.datetime): + seconds = float(str(value.second) + "." + + str(value.microsecond)) + return kinterbasdb.date_conv_out((value.year, value.month, value.day, + value.hour, value.minute, seconds)) + return kinterbasdb.timestamp_conv_in(value) + else: + return None </ins><span class="cx"> class FBText(sqltypes.TEXT): </span><span class="cx"> def get_col_spec(self): </span><span class="cx"> return "BLOB SUB_TYPE 2" </span><span class="lines">@@ -74,13 +84,12 @@ </span><span class="cx"> ]} </span><span class="cx"> </span><span class="cx"> class FBSQLEngine(ansisql.ANSISQLEngine): </span><del>- def __init__(self, opts, use_ansi = True, module = None, **params): - self._use_ansi = use_ansi - self.opts = opts or {} </del><ins>+ def __init__(self, opts, module=None, use_oids=False, **params): </ins><span class="cx"> if module is None: </span><span class="cx"> self.module = kinterbasdb </span><span class="cx"> else: </span><span class="cx"> self.module = module </span><ins>+ self.opts = self._translate_connect_args(('host', 'database', 'user', 'password'), opts) </ins><span class="cx"> ansisql.ANSISQLEngine.__init__(self, **params) </span><span class="cx"> </span><span class="cx"> def do_commit(self, connection): </span><span class="lines">@@ -102,7 +111,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(statement, bindparams, engine=self, use_ansi=self._use_ansi, **kwargs) </del><ins>+ return FBCompiler(statement, bindparams, engine=self, **kwargs) </ins><span class="cx"> </span><span class="cx"> def schemagenerator(self, **params): </span><span class="cx"> return FBSchemaGenerator(self, **params) </span><span class="lines">@@ -188,21 +197,6 @@ </span><span class="cx"> class FBCompiler(ansisql.ANSICompiler): </span><span class="cx"> """firebird compiler modifies the lexical structure of Select statements to work under </span><span class="cx"> non-ANSI configured Firebird databases, if the use_ansi flag is False.""" </span><del>- - 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) - </del><span class="cx"> def visit_function(self, func): </span><span class="cx"> if len(func.clauses): </span><span class="cx"> super(FBCompiler, self).visit_function(func) </span><span class="lines">@@ -223,10 +217,11 @@ </span><span class="cx"> """ called when building a SELECT statment, position is just before column list </span><span class="cx"> Firebird puts the limit and offset right after the select...thanks for adding the </span><span class="cx"> visit_select_precolumns!!!""" </span><ins>+ result = '' </ins><span class="cx"> if select.offset: </span><del>- result +=" FIRST " + select.offset </del><ins>+ result +=" FIRST %s " % select.offset </ins><span class="cx"> if select.limit: </span><del>- result += " SKIP " + select.limit </del><ins>+ result += " SKIP %s " % select.limit </ins><span class="cx"> if select.distinct: </span><span class="cx"> result += " DISTINCT " </span><span class="cx"> return result </span><span class="lines">@@ -234,6 +229,8 @@ </span><span class="cx"> def limit_clause(self, select): </span><span class="cx"> """Already taken care of in the visit_select_precolumns method.""" </span><span class="cx"> return "" </span><ins>+ def default_from(self): + return ' from RDB$DATABASE ' </ins><span class="cx"> </span><span class="cx"> class FBSchemaGenerator(ansisql.ANSISchemaGenerator): </span><span class="cx"> def get_column_specification(self, column, override_pk=False, **kwargs): </span></span></pre> </div> </div> </body> </html> |