Add explicit joins (and possibility for left-joins) for columns missing a...

Add explicit joins (and possibility for left-joins) for columns missing a related-key search at build time

git-svn-id: https://svn.erp5.org/repos/public/erp5/sandbox/catalog_join@42781 20353a03-c40f-0410-a6d1-a30d3c3de9de
parent 631cab2b
...@@ -94,7 +94,7 @@ class ColumnMap(object): ...@@ -94,7 +94,7 @@ class ColumnMap(object):
self.raw_column_dict = {} self.raw_column_dict = {}
# Entries: column name # Entries: column name
self.column_ignore_set = set() self.column_ignore_set = set()
self.join_table_set = set() self.join_table_map = dict()
# BBB: Remove join_query_list and its uses when all RelatedKey # BBB: Remove join_query_list and its uses when all RelatedKey
# methods have been converted to properly return each Join # methods have been converted to properly return each Join
# condition separately, and all uses of catalog's from_expression # condition separately, and all uses of catalog's from_expression
...@@ -146,7 +146,7 @@ class ColumnMap(object): ...@@ -146,7 +146,7 @@ class ColumnMap(object):
# When a column is registered in default group and is explicitely # When a column is registered in default group and is explicitely
# mapped to a table, we must mark its table as requiring a join with # mapped to a table, we must mark its table as requiring a join with
# catalog table (unless it's the catalog table, of course). # catalog table (unless it's the catalog table, of course).
self._addJoinTable(table, group) self._addJoinTableForColumn(table, table + "." + column, group)
def ignoreColumn(self, column): def ignoreColumn(self, column):
self.column_ignore_set.add(column) self.column_ignore_set.add(column)
...@@ -281,7 +281,7 @@ class ColumnMap(object): ...@@ -281,7 +281,7 @@ class ColumnMap(object):
# Although the list of tables those columns belong to is known # Although the list of tables those columns belong to is known
# earlier (in "build"), mapping them here # earlier (in "build"), mapping them here
# - avoids code duplication (registerTable, resolveColumn, # - avoids code duplication (registerTable, resolveColumn,
# _addJoinTable) # _addJoinTableForColumn)
# - offers user to vote for an unknown table, overriding this # - offers user to vote for an unknown table, overriding this
# forced mapping. # forced mapping.
use_allowed = table_name == catalog_table_name or \ use_allowed = table_name == catalog_table_name or \
...@@ -326,7 +326,7 @@ class ColumnMap(object): ...@@ -326,7 +326,7 @@ class ColumnMap(object):
self.registerTable(table_name, group=group) self.registerTable(table_name, group=group)
self.resolveColumn(column_name, table_name, group=group) self.resolveColumn(column_name, table_name, group=group)
if table_name != catalog_table_name: if table_name != catalog_table_name:
self._addJoinTable(table_name, group) self._addJoinTableForColumn(table_name, column_name, group)
@profiler_decorator @profiler_decorator
def build(self, sql_catalog): def build(self, sql_catalog):
...@@ -424,9 +424,9 @@ class ColumnMap(object): ...@@ -424,9 +424,9 @@ class ColumnMap(object):
table_alias_number_dict[alias_table_name] = table_alias_number table_alias_number_dict[alias_table_name] = table_alias_number
self.resolveTable(table_name, alias, group=group) self.resolveTable(table_name, alias, group=group)
# now that we have all aliases, calculate inner joins comming from # now that we have all aliases, calculate missing joins comming from
# non-RelatedKey relationships (like full_text). # non-RelatedKey relationships (like full_text).
self._calculateInnerJoins() self._calculateMissingJoins()
# and all left joins that did not come from explicit queries # and all left joins that did not come from explicit queries
# (i.e. joins comming from 'sort_on', 'select_dict', etc.) # (i.e. joins comming from 'sort_on', 'select_dict', etc.)
for join_query in join_query_to_build_list: for join_query in join_query_to_build_list:
...@@ -553,7 +553,7 @@ class ColumnMap(object): ...@@ -553,7 +553,7 @@ class ColumnMap(object):
@profiler_decorator @profiler_decorator
def _addJoinTable(self, table_name, group=DEFAULT_GROUP_ID): def _addJoinTableForColumn(self, table_name, column, group=DEFAULT_GROUP_ID):
""" """
Declare given table as requiring to be joined with catalog table on uid. Declare given table as requiring to be joined with catalog table on uid.
...@@ -571,11 +571,11 @@ class ColumnMap(object): ...@@ -571,11 +571,11 @@ class ColumnMap(object):
# Register uid column if it is not already # Register uid column if it is not already
self.registerColumn('uid') self.registerColumn('uid')
self.resolveColumn('uid', catalog_table) self.resolveColumn('uid', catalog_table)
self.join_table_set.add((group, table_name)) self.join_table_map.setdefault((group, table_name), set()).add(column)
def getJoinTableAliasList(self): def getJoinTableAliasList(self):
return [self.getTableAlias(table_name, group=group) return [self.getTableAlias(table_name, group=group)
for (group, table_name) in self.join_table_set] for (group, table_name) in self.join_table_map.keys()]
def _getTableOverride(self, table_name): def _getTableOverride(self, table_name):
# self.table_override_map is a dictionary mapping table names to # self.table_override_map is a dictionary mapping table names to
...@@ -671,20 +671,31 @@ class ColumnMap(object): ...@@ -671,20 +671,31 @@ class ColumnMap(object):
self.table_definition = join_definition self.table_definition = join_definition
# def getFinalTableDefinition(self): # def getFinalTableDefinition(self):
# self._calculateInnerJoins() # self._calculateMissingJoins()
# return self.getTableDefinition() # return self.getTableDefinition()
def _calculateInnerJoins(self): def _calculateMissingJoins(self):
left_join_set = set(self.left_join_list)
self._setMinimalTableDefinition() self._setMinimalTableDefinition()
catalog_table_alias = self.getCatalogTableAlias() catalog_table_alias = self.getCatalogTableAlias()
for group, table_name in self.join_table_set: for (group, table_name), column_set in self.join_table_map.items():
# if any of the columns for this implicit join was requested as a
#left-join, then all columns will be subject to a left-join.
# XXX What if one of the columns was an actual query, as opposed to a
# sort column or select_dict? This would cause results in the main
# catalog that don't match the query to be present as well. We expect
# the user which passes a left_join_list to know what he is doing.
if column_set.intersection(left_join_set):
Join = LeftJoin
else:
Join = InnerJoin
table_alias = self.getTableAlias(table_name, group=group) table_alias = self.getTableAlias(table_name, group=group)
table_alias_def = self.makeTableAliasDefinition(table_name, table_alias) table_alias_def = self.makeTableAliasDefinition(table_name, table_alias)
# XXX: perhaps refactor some of the code below to do: # XXX: perhaps refactor some of the code below to do:
# self._inner_table_definition.addInnerJoin(TableAlias(...), # self._inner_table_definition.addInnerJoin(TableAlias(...),
# condition=(...)) # condition=(...))
self._inner_table_definition.replace( self._inner_table_definition.replace(
InnerJoin(self._inner_table_definition.table_definition, Join(self._inner_table_definition.table_definition,
table_alias_def, table_alias_def,
# XXX ColumnMap shouldn't have SQL knowledge # XXX ColumnMap shouldn't have SQL knowledge
condition=('`%s`.`uid` = `%s`.`uid`' % condition=('`%s`.`uid` = `%s`.`uid`' %
......
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