section_category=context.getGroup(base=1), strict_base_contribution_uid=base_contribution_uid_dict.values(), portal_type=portal_type, parent_portal_type=delivery_portal_type, simulation_state=('stopped', 'delivered'), mirror_date=dict(query=context.getStopDate(), range='ngt'), only_accountable=only_accountable, ) if context.getValidationState() == 'validated': inventory_kw['default_aggregate_uid'] = context.getUid() else: aggregate_base_category_uid = portal.portal_categories.aggregate.getUid() # TODO include context portal type inventory_kw['where_expression'] = SQLQuery( '(SELECT COUNT(uid) from category where ' 'base_category_uid=%s and uid=stock.uid) = 0' % aggregate_base_category_uid) # get all resources that have been used with this inventory parameters resource_list = [ brain.resource_relative_url for brain in portal.portal_simulation.getInventoryList(group_by_node=0, group_by_section=0, group_by_resource=1, **inventory_kw) ] for resource_relative_url in resource_list: resource = portal.restrictedTraverse(resource_relative_url) inventory_kw['resource_uid'] = resource.getUid(),
def buildSQLQuery(self, strict_membership=0, table='category', join_table='catalog', join_column='uid', **kw): """ A Predicate can be rendered as an SQL expression. This can be used to generate SQL requests in reports or in catalog search queries. XXX - This method is not implemented yet """ # Build the identity criterion catalog_kw = {} catalog_kw.update(kw) # query_table, REQUEST, ignore_empty_string, **kw criterion_list = self.getCriterionList() # BBB: accessor is not present on old Predicate property sheet. if criterion_list or getattr(self, 'isEmptyPredicateValid', lambda: True)(): for criterion in criterion_list: if criterion.min and criterion.max: catalog_kw[criterion.property] = { 'query' : (criterion.min, criterion.max), 'range' : 'minmax' } elif criterion.min: catalog_kw[criterion.property] = { 'query' : criterion.min, 'range' : 'min' } elif criterion.max: catalog_kw[criterion.property] = { 'query' : criterion.max, 'range' : 'max' } else: # if a filter was passed as argument if catalog_kw.has_key(criterion.property): if isinstance(catalog_kw[criterion.property], (tuple, list)): catalog_filter_set = set(catalog_kw[criterion.property]) else: catalog_filter_set = set([catalog_kw[criterion.property]]) if isinstance(criterion.identity, (tuple, list)): parameter_filter_set = set(criterion.identity) else: parameter_filter_set = set([criterion.identity]) catalog_kw[criterion.property] = \ list(catalog_filter_set.intersection(parameter_filter_set)) else: catalog_kw[criterion.property] = criterion.identity else: # By catalog definition, no object has uid 0, so this condition forces an # empty result. catalog_kw['uid'] = 0 portal_catalog = getToolByName(self, 'portal_catalog') from_table_dict = {} # First build SQL for membership criteria # It would be much nicer if all this was handled by the catalog in a central place membership_dict = {} for base_category in self.getMembershipCriterionBaseCategoryList(): membership_dict[base_category] = [] # Init dict with valid base categories for category in self.getMembershipCriterionCategoryList(): base_category = category.split('/')[0] # Retrieve base category if membership_dict.has_key(base_category): category_value = self._unrestrictedResolveCategory(category, None) if category_value is not None: table_alias = "single_%s_%s" % (table, base_category) from_table_dict[table_alias] = 'category' membership_dict[base_category].append(category_value.asSQLExpression( strict_membership=strict_membership, table=table_alias, base_category=base_category)) membership_select_list = [] for expression_list in membership_dict.values(): or_expression = ' OR '.join(expression_list) if or_expression: membership_select_list.append('( %s )' % or_expression) # Then build SQL for multimembership_dict criteria multimembership_dict = {} for base_category in self.getMultimembershipCriterionBaseCategoryList(): multimembership_dict[base_category] = [] # Init dict with valid base categories join_count = 0 for category in self.getMembershipCriterionCategoryList(): base_category = category.split('/')[0] # Retrieve base category if multimembership_dict.has_key(base_category): category_value = self._unrestrictedResolveCategory(category) if category_value is not None: join_count += 1 table_alias = "multi_%s_%s" % (table, join_count) from_table_dict[table_alias] = 'category' multimembership_dict[base_category].append(category_value.asSQLExpression( strict_membership=strict_membership, table=table_alias, base_category=base_category)) multimembership_select_list = [] for expression_list in multimembership_dict.values(): and_expression = ' AND '.join(expression_list) if and_expression: multimembership_select_list.append(and_expression) # Build the join where expression join_select_list = [] for k in from_table_dict.iterkeys(): join_select_list.append('%s.%s = %s.uid' % (join_table, join_column, k)) sql_text = ' AND '.join(join_select_list + membership_select_list + multimembership_select_list) # Now merge identity and membership criteria if len(sql_text): catalog_kw['where_expression'] = SQLQuery(sql_text) else: catalog_kw['where_expression'] = '' # force implicit join catalog_kw['implicit_join'] = True sql_query = portal_catalog.buildSQLQuery(**catalog_kw) # XXX from_table_list is None most of the time after the explicit_join work for alias, table in sql_query['from_table_list']: if from_table_dict.has_key(alias): raise KeyError, "The same table is used twice for an identity criterion and for a membership criterion" from_table_dict[alias] = table sql_query['from_table_list'] = from_table_dict.items() return sql_query
def _searchPredicateList(self, context, test=1, sort_method=None, ignored_category_list=None, tested_base_category_list=None, filter_method=None, acquired=1, strict=True, sort_key_method=None, query=None, restricted=False, **kw): # XXX: about "strict" parameter: This is a transition parameter, # allowing someone hitting a bug to revert to original behaviour easily. # It is not a correct name, as pointed out by Jerome. But instead of # searching for another name, it would be much better to just remove it. """ Search all predicates which corresponds to this particular context. - sort_method parameter should not be used, if possible, because it can be very slow. Use sort_key_method instead. - sort_key_method parameter is passed to list.sort as key parameter if it is not None. This allows to sort the list of predicates found. The most important predicate is the first one in the list. - ignored_category_list: this is the list of category that we do not want to test. For example, we might want to not test the destination or the source of a predicate. - tested_base_category_list: this is the list of category that we do want to test. For example, we might want to test only the destination or the source of a predicate. - the acquired parameter allows to define if we want to use acquisition for categories. By default we want. - strict: if True, generate SQL which will match predicates matching all those categories at the same time, except for categories they do not check at all. Example: Predicate_1 checks foo/bar Predicate_2 checks foo/baz region/somewhere Predicate_3 checks foo/bar region/somewhere When called with category list ['foo/bar', 'region/somewhere'] and strict parameter to True, it will return [Predicate_1, Predicate_3]. With strict to False or by not giving a category list, it would also return Predicate_2, because it matches on one criterion out of the 2 it checks. Note that it changes the value returned by this function if it was invoked with "test=False" value. Otherwise, it should only change execution duration. """ portal = self.getPortalObject() portal_catalog = portal.portal_catalog portal_categories = portal.portal_categories # Search the columns of the predicate table range_column_set = set() query_list = [] if query is None else [query] for column in portal_catalog.getColumnIds(): if column[:10] == 'predicate.' and \ column[-10:] in ('_range_min', '_range_max'): property_name = column[10:-10] if property_name not in range_column_set: range_column_set.add(property_name) # We have to check a range property equality = 'predicate.' + property_name range_min = equality + '_range_min' range_max = equality + '_range_max' value = context.getProperty(property_name) query = ComplexQuery(Query(**{equality: None}), Query(**{range_min: None}), Query(**{range_max: None}), logical_operator='AND') if value is not None: query = ComplexQuery( query, ComplexQuery( Query(**{equality: value}), ComplexQuery( ComplexQuery( Query( **{ range_min: dict( query=value, range='ngt', ) }), Query(**{range_max: None}), logical_operator='AND', ), ComplexQuery( Query(**{range_min: None}), Query( **{ range_max: dict( query=value, range='min', ) }), logical_operator='AND', ), ComplexQuery( Query( **{ range_min: dict( query=value, range='ngt', ) }), Query( **{ range_max: dict( query=value, range='min', ) }), logical_operator='AND', ), logical_operator='OR', ), logical_operator='OR', ), logical_operator='OR') query_list.append(query) # Add category selection if tested_base_category_list is None: if acquired: category_list = context.getAcquiredCategoryList() else: category_list = context.getCategoryList() else: if acquired: getter = context.getAcquiredCategoryMembershipList else: getter = context.getCategoryMembershipList category_list = [] extend = category_list.extend for tested_base_category in tested_base_category_list: extend(getter(tested_base_category, base=1)) if tested_base_category_list != []: preferred_predicate_category_list = portal.portal_preferences.getPreferredPredicateCategoryList( ) if (preferred_predicate_category_list and tested_base_category_list is not None and set(preferred_predicate_category_list).issuperset( tested_base_category_list)): # New behavior is enabled only if preferred predicate category is # defined and tested_base_category_list is passed. predicate_category_query_list = [] predicate_category_table_name_list = [] category_dict = {} for relative_url in category_list: category_value = portal_categories.getCategoryValue( relative_url) base_category_id = portal_categories.getBaseCategoryId( relative_url) base_category_value = portal_categories.getCategoryValue( base_category_id) if not base_category_value in category_dict: category_dict[base_category_value] = [] category_dict[base_category_value].append(category_value) for base_category_value, category_value_list in category_dict.iteritems( ): if base_category_value.getId( ) in preferred_predicate_category_list: table_index = len(predicate_category_query_list) predicate_category_table_name = 'predicate_category_for_domain_tool_%s' % table_index table_alias_list = [('predicate_category', predicate_category_table_name)] predicate_category_query_list.append( ComplexQuery( Query(predicate_category_base_category_uid= base_category_value.getUid(), table_alias_list=table_alias_list), Query( predicate_category_category_strict_membership =1, table_alias_list=table_alias_list), ComplexQuery( Query(predicate_category_category_uid=[ category_value.getUid() for category_value in category_value_list ], table_alias_list=table_alias_list), Query( predicate_category_category_uid='NULL', table_alias_list=table_alias_list), logical_operator='OR'), logical_operator='AND')) if not predicate_category_query_list: # Prevent matching everything predicate_category_query_list.append( Query(predicate_category_base_category_uid=0)) predicate_category_query = ComplexQuery( logical_operator='AND', *predicate_category_query_list) query_list.append(predicate_category_query) else: # Traditional behavior category_expression_dict = portal_categories.buildAdvancedSQLSelector( category_list or ['NULL'], query_table='predicate_category', none_sql_value=0, strict=strict) where_expression = category_expression_dict['where_expression'] if where_expression: kw['where_expression'] = SQLQuery(where_expression) if 'from_expression' in category_expression_dict: kw['from_expression'] = category_expression_dict[ 'from_expression'] else: # Add predicate_category.uid for automatic join kw['predicate_category.uid'] = '!=NULL' if query_list: kw['query'] = ComplexQuery(logical_operator='AND', *query_list) if restricted: sql_result_list = portal_catalog.searchResults(**kw) else: sql_result_list = portal_catalog.unrestrictedSearchResults(**kw) if kw.get('src__'): return sql_result_list result_list = [] for predicate in sql_result_list: predicate = predicate.getObject() if (not test) or predicate.test( context, tested_base_category_list=tested_base_category_list): result_list.append(predicate) if filter_method is not None: result_list = filter_method(result_list) if sort_key_method is not None: result_list.sort(key=sort_key_method) elif sort_method is not None: result_list.sort(cmp=sort_method) return result_list