From: Mike Bayer Date: Fri, 3 Aug 2007 18:47:35 +0000 (+0000) Subject: small fix for filter() aliasing, upgraded elementtree examples to use 0.4 style queries X-Git-Tag: rel_0_4beta1~90 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b9a7fc23da7a7e4403ea9b32d7dba5d72d750e81;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git small fix for filter() aliasing, upgraded elementtree examples to use 0.4 style queries --- diff --git a/examples/elementtree/adjacency_list.py b/examples/elementtree/adjacency_list.py index 204662f561..af9084a448 100644 --- a/examples/elementtree/adjacency_list.py +++ b/examples/elementtree/adjacency_list.py @@ -26,7 +26,7 @@ from elementtree import ElementTree from elementtree.ElementTree import Element, SubElement meta = MetaData() -meta.engine = 'sqlite://' +meta.bind = 'sqlite://' ################################# PART II - Table Metadata ########################################### @@ -174,12 +174,10 @@ print document ############################################ PART VI - Searching for Paths ####################################### # manually search for a document which contains "/somefile/header/field1:hi" -print "\nManual search for /somefile/header/field1=='hi':", line -n1 = elements.alias('n1') -n2 = elements.alias('n2') -n3 = elements.alias('n3') -j = documents.join(n1).join(n2, n1.c.element_id==n2.c.parent_id).join(n3, n2.c.element_id==n3.c.parent_id) -d = session.query(Document).select_from(j).filter(n1.c.tag=='somefile').filter(n2.c.tag=='header').filter(and_(n3.c.tag=='field1', n3.c.text=='hi')).one() +d = session.query(Document).join('_root', aliased=True).filter(_Node.tag=='somefile').\ + join('children', aliased=True, from_joinpoint=True).filter(_Node.tag=='header').\ + join('children', aliased=True, from_joinpoint=True).filter(and_(_Node.tag=='field1', _Node.text=='hi')).\ + one() print d # generalize the above approach into an extremely impoverished xpath function: @@ -187,22 +185,17 @@ def find_document(path, compareto): j = documents prev_elements = None query = session.query(Document) + attribute = '_root' for i, match in enumerate(re.finditer(r'/([\w_]+)(?:\[@([\w_]+)(?:=(.*))?\])?', path)): (token, attrname, attrvalue) = match.group(1, 2, 3) - a = elements.alias("n%d" % i) - query = query.filter(a.c.tag==token) + query = query.join(attribute, aliased=True, from_joinpoint=True).filter(_Node.tag==token) + attribute = 'children' if attrname: - attr_alias = attributes.alias('a%d' % i) if attrvalue: - query = query.filter(and_(a.c.element_id==attr_alias.c.element_id, attr_alias.c.name==attrname, attr_alias.c.value==attrvalue)) + query = query.join('attributes', aliased=True, from_joinpoint=True).filter(and_(_Attribute.name==attrname, _Attribute.value==attrvalue)) else: - query = query.filter(and_(a.c.element_id==attr_alias.c.element_id, attr_alias.c.name==attrname)) - if prev_elements is not None: - j = j.join(a, prev_elements.c.element_id==a.c.parent_id) - else: - j = j.join(a) - prev_elements = a - return query.options(lazyload('_root')).select_from(j).filter(prev_elements.c.text==compareto).all() + query = query.join('attributes', aliased=True, from_joinpoint=True).filter(_Attribute.name==attrname) + return query.options(lazyload('_root')).filter(_Node.text==compareto).all() for path, compareto in ( ('/somefile/header/field1', 'hi'), diff --git a/examples/elementtree/optimized_al.py b/examples/elementtree/optimized_al.py index 17b6489de0..5666f879a1 100644 --- a/examples/elementtree/optimized_al.py +++ b/examples/elementtree/optimized_al.py @@ -18,14 +18,14 @@ logging.basicConfig() #logging.getLogger('sqlalchemy.engine').setLevel(logging.INFO) # uncomment to show SQL statements and result sets -logging.getLogger('sqlalchemy.engine').setLevel(logging.DEBUG) +#logging.getLogger('sqlalchemy.engine').setLevel(logging.DEBUG) from elementtree import ElementTree from elementtree.ElementTree import Element, SubElement meta = MetaData() -meta.engine = 'sqlite://' +meta.bind = 'sqlite://' ################################# PART II - Table Metadata ########################################### @@ -94,7 +94,7 @@ mapper(Document, documents, properties={ }) # the _Node objects change the way they load so that a list of _Nodes will organize -# themselves hierarchically using the HierarchicalLoader. this depends on the ordering of +# themselves hierarchically using the ElementTreeMarshal. this depends on the ordering of # nodes being hierarchical as well; relation() always applies at least ROWID/primary key # ordering to rows which will suffice. mapper(_Node, elements, properties={ @@ -184,11 +184,10 @@ print document # manually search for a document which contains "/somefile/header/field1:hi" print "\nManual search for /somefile/header/field1=='hi':", line -n1 = elements.alias('n1') -n2 = elements.alias('n2') -n3 = elements.alias('n3') -j = documents.join(n1).join(n2, n1.c.element_id==n2.c.parent_id).join(n3, n2.c.element_id==n3.c.parent_id) -d = session.query(Document).select_from(j).filter(n1.c.tag=='somefile').filter(n2.c.tag=='header').filter(and_(n3.c.tag=='field1', n3.c.text=='hi')).one() +d = session.query(Document).join('_nodes', aliased=True).filter(and_(_Node.parent_id==None, _Node.tag=='somefile')).\ + join('children', aliased=True, from_joinpoint=True).filter(_Node.tag=='header').\ + join('children', aliased=True, from_joinpoint=True).filter(and_(_Node.tag=='field1', _Node.text=='hi')).\ + one() print d # generalize the above approach into an extremely impoverished xpath function: @@ -196,22 +195,22 @@ def find_document(path, compareto): j = documents prev_elements = None query = session.query(Document) + first = True for i, match in enumerate(re.finditer(r'/([\w_]+)(?:\[@([\w_]+)(?:=(.*))?\])?', path)): (token, attrname, attrvalue) = match.group(1, 2, 3) - a = elements.alias("n%d" % i) - query = query.filter(a.c.tag==token) + if first: + query = query.join('_nodes', aliased=True).filter(_Node.parent_id==None) + first = False + else: + query = query.join('children', aliased=True, from_joinpoint=True) + query = query.filter(_Node.tag==token) if attrname: - attr_alias = attributes.alias('a%d' % i) + query = query.join('attributes', aliased=True, from_joinpoint=True) if attrvalue: - query = query.filter(and_(a.c.element_id==attr_alias.c.element_id, attr_alias.c.name==attrname, attr_alias.c.value==attrvalue)) + query = query.filter(and_(_Attribute.name==attrname, _Attribute.value==attrvalue)) else: - query = query.filter(and_(a.c.element_id==attr_alias.c.element_id, attr_alias.c.name==attrname)) - if prev_elements is not None: - j = j.join(a, prev_elements.c.element_id==a.c.parent_id) - else: - j = j.join(a) - prev_elements = a - return query.options(lazyload('_nodes')).select_from(j).filter(prev_elements.c.text==compareto).all() + query = query.filter(_Attribute.name==attrname) + return query.options(lazyload('_nodes')).filter(_Node.text==compareto).all() for path, compareto in ( ('/somefile/header/field1', 'hi'), diff --git a/lib/sqlalchemy/orm/util.py b/lib/sqlalchemy/orm/util.py index 727be50c61..e9fe6ac4ef 100644 --- a/lib/sqlalchemy/orm/util.py +++ b/lib/sqlalchemy/orm/util.py @@ -211,8 +211,7 @@ class AliasedClauses(object): return aliased_column def adapt_clause(self, clause): - return self.aliased_column(clause) -# return sql_util.ClauseAdapter(self.alias).traverse(clause, clone=True) + return sql_util.ClauseAdapter(self.alias).traverse(clause, clone=True) def _create_row_adapter(self): """Return a callable which, diff --git a/test/orm/query.py b/test/orm/query.py index 3c9d143201..e01c0e67d8 100644 --- a/test/orm/query.py +++ b/test/orm/query.py @@ -421,6 +421,9 @@ class JoinTest(QueryTest): q = sess.query(User).join('addresses', aliased=True).filter(Address.email_address=='jack@bean.com') assert [User(id=7)] == q.all() + q = sess.query(User).join('addresses', aliased=True).filter(or_(Address.email_address=='jack@bean.com', Address.email_address=='fred@fred.com')) + assert [User(id=7), User(id=9)] == q.all() + # test two aliasized paths, one to 'orders' and the other to 'orders','items'. # one row is returned because user 7 has order 3 and also has order 1 which has item 1 # this tests a o2m join and a m2m join.