activate backward compatibility mode when receiving a from_expression

git-svn-id: https://svn.erp5.org/repos/public/erp5/sandbox/catalog_join@42522 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 8b22b59a
...@@ -94,8 +94,10 @@ class ColumnMap(object): ...@@ -94,8 +94,10 @@ class ColumnMap(object):
# Entries: column name # Entries: column name
self.column_ignore_set = set() self.column_ignore_set = set()
self.join_table_set = set() self.join_table_set = set()
# BBB: Remove join_query_list and its uses when all RelatedKey methods have # BBB: Remove join_query_list and its uses when all RelatedKey
# been converted to properly return each Join condition separately. # methods have been converted to properly return each Join
# condition separately, and all uses of catalog's from_expression
# have been removed.
self.join_query_list = [] self.join_query_list = []
self.table_override_map = table_override_map or {} self.table_override_map = table_override_map or {}
self.table_definition = PlaceHolderTableDefinition() self.table_definition = PlaceHolderTableDefinition()
...@@ -474,9 +476,21 @@ class ColumnMap(object): ...@@ -474,9 +476,21 @@ class ColumnMap(object):
def getCatalogTableAlias(self, group=DEFAULT_GROUP_ID): def getCatalogTableAlias(self, group=DEFAULT_GROUP_ID):
return self.table_alias_dict[(group, self.catalog_table_name)] return self.table_alias_dict[(group, self.catalog_table_name)]
def _isBackwardCompatibilityRequired(self):
return bool(
# If one or more RelatedKey methods weren't converted, we'll get
# queries for an implicit inner join, so we have to do all joins
# as implicit.
self.join_query_list
# for now, work in BW compat mode if a table_override
# is passed. It only works for simple subselect
# definitions anyway, and it's being used primarily
# for writing left-joins manually.
or self.table_override_map)
def getTableAliasDict(self): def getTableAliasDict(self):
if self.join_query_list: if self._isBackwardCompatibilityRequired():
# BBB: Using implicit joins # BBB: Using implicit joins or explicit from_expression
return self.table_map.copy() return self.table_map.copy()
else: else:
return None return None
...@@ -521,10 +535,9 @@ class ColumnMap(object): ...@@ -521,10 +535,9 @@ class ColumnMap(object):
self.join_query_list.append(query) self.join_query_list.append(query)
def iterJoinQueryList(self): def iterJoinQueryList(self):
if self.join_query_list: if self._isBackwardCompatibilityRequired():
# BBB: one or more RelatedKey methods weren't converted, so we got # Return all join queries for implicit join, and all the other
# queries for an implicit inner join. Return them, and all the other # queries we were using to build explicit joins, but won't be able to.
# queries we were using in our table definition
return itertools.chain(self.join_query_list, return itertools.chain(self.join_query_list,
self.table_definition.getJoinConditionQueryList()) self.table_definition.getJoinConditionQueryList())
return [] return []
...@@ -615,7 +628,7 @@ class ColumnMap(object): ...@@ -615,7 +628,7 @@ class ColumnMap(object):
def getTableDefinition(self): def getTableDefinition(self):
if not self._setMinimalTableDefinition(): if not self._setMinimalTableDefinition():
raise RuntimeError("ColumnMap.build() must be called first!") raise RuntimeError("ColumnMap.build() must be called first!")
if self.join_query_list: if self._isBackwardCompatibilityRequired():
# BBB: One of the RelatedKeys registered an implicit join, do # BBB: One of the RelatedKeys registered an implicit join, do
# not return a table definition, self.getTableAliasDict() should # not return a table definition, self.getTableAliasDict() should
# be used instead # be used instead
......
...@@ -35,6 +35,7 @@ from Products.ZSQLCatalog.interfaces.entire_query import IEntireQuery ...@@ -35,6 +35,7 @@ from Products.ZSQLCatalog.interfaces.entire_query import IEntireQuery
from zope.interface.verify import verifyClass from zope.interface.verify import verifyClass
from zope.interface import implements from zope.interface import implements
from Products.ZSQLCatalog.SQLCatalog import profiler_decorator from Products.ZSQLCatalog.SQLCatalog import profiler_decorator
from Products.ZSQLCatalog.TableDefinition import LegacyTableDefinition
def defaultDict(value): def defaultDict(value):
if value is None: if value is None:
...@@ -182,16 +183,27 @@ class EntireQuery(object): ...@@ -182,16 +183,27 @@ class EntireQuery(object):
# append(SQLExpression(self, where_expression=' AND '.join( # append(SQLExpression(self, where_expression=' AND '.join(
# where_pattern % (x, ) for x in join_table_list # where_pattern % (x, ) for x in join_table_list
# ))) # )))
self.from_expression = column_map.getTableDefinition()
# BBB self.from_expression forces use of implicit inner join
table_alias_dict = column_map.getTableAliasDict() table_alias_dict = column_map.getTableAliasDict()
assert ((self.from_expression is None) != if self.from_expression:
(table_alias_dict is None)), ("Got both a from_expression " # XXX: perhaps move this code to ColumnMap?
"and a table_alias_dict") legacy_from_expression = self.from_expression
from_expression = LegacyTableDefinition(legacy_from_expression,
table_alias_dict)
table_alias_dict = None
else:
from_expression = column_map.getTableDefinition()
assert ((from_expression is None) !=
(table_alias_dict is None)), ("Got both a from_expression "
"and a table_alias_dict")
self.sql_expression_list = sql_expression_list self.sql_expression_list = sql_expression_list
# TODO: wrap the table_alias_dict above into a TableDefinition as well,
# even without a legacy_table_definition.
return SQLExpression( return SQLExpression(
self, self,
table_alias_dict=table_alias_dict, table_alias_dict=table_alias_dict,
from_expression=self.from_expression, from_expression=from_expression,
order_by_list=self.order_by_list, order_by_list=self.order_by_list,
group_by_list=self.group_by_list, group_by_list=self.group_by_list,
select_dict=self.final_select_dict, select_dict=self.final_select_dict,
......
...@@ -403,12 +403,6 @@ class SQLExpression(object): ...@@ -403,12 +403,6 @@ class SQLExpression(object):
"and a from_table_list") "and a from_table_list")
if from_expression is not None: if from_expression is not None:
from_expression = from_expression.render() from_expression = from_expression.render()
# from_expression_dict = from_expression
# from_expression = SQL_LIST_SEPARATOR.join(
# from_expression_dict.get(table, '`%s` AS `%s`' % (table, alias))
# for alias, table in table_alias_dict.iteritems())
# else:
# from_expression = None
return { return {
'where_expression': self.getWhereExpression(), 'where_expression': self.getWhereExpression(),
'order_by_expression': self.getOrderByExpression(), 'order_by_expression': self.getOrderByExpression(),
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
# * collapse of parentheses around chains of inner-joins # * collapse of parentheses around chains of inner-joins
# * indentation on rendering # * indentation on rendering
SQL_LIST_SEPARATOR = ', '
SQL_SELECT_ALIAS_FORMAT = '%s AS `%s`' SQL_SELECT_ALIAS_FORMAT = '%s AS `%s`'
from Products.ZSQLCatalog.Query.SQLQuery import SQLQuery from Products.ZSQLCatalog.Query.SQLQuery import SQLQuery
...@@ -200,3 +201,22 @@ class LeftJoin(InnerJoin): ...@@ -200,3 +201,22 @@ class LeftJoin(InnerJoin):
"inner join, but this table definition contains a Left " "inner join, but this table definition contains a Left "
"Join: %r" % self) "Join: %r" % self)
class LegacyTableDefinition(TableDefinition):
"""Table Definition used when a from_expression is passed explicitly.
Mostly used for manual left-join definitions. Deprecated
"""
def __init__(self, from_expression, table_alias_map):
self.from_expression = from_expression
self.table_alias_map = table_alias_map
def checkTableAliases(self, current_aliases=None):
pass
def render(self):
from_expression_dict = self.from_expression
table_alias_map = self.table_alias_map
from_expression = SQL_LIST_SEPARATOR.join(
from_expression_dict.get(table, '`%s` AS `%s`' % (table, alias))
for alias, table in table_alias_map.iteritems())
return from_expression
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment