def _set_operator_specified_filters(self, operator): """Set any filters using AND instead of OR.""" filters = QueryFilterCollection() composed_filter = Q() for filter_key in self.SUPPORTED_FILTERS: operator_key = operator + ":" + filter_key filter_value = self.parameters.get_filter(operator_key) logical_operator = operator if filter_value and len(filter_value) < 2: logical_operator = "or" if filter_value and not OrgQueryHandler.has_wildcard(filter_value): filter_obj = self.FILTER_MAP.get(filter_key) if isinstance(filter_obj, list): for _filt in filter_obj: filt_filters = QueryFilterCollection() for item in filter_value: q_filter = QueryFilter(parameter=item, logical_operator=logical_operator, **_filt) filt_filters.add(q_filter) composed_filter = composed_filter | filt_filters.compose() else: for item in filter_value: q_filter = QueryFilter(parameter=item, logical_operator=logical_operator, **filter_obj) filters.add(q_filter) if filters: composed_filter = composed_filter & filters.compose() return composed_filter
def test_set_access_filters_with_list(self): """Test that the execute query runs properly with value query and an RBAC restriction on cluster.""" key = "app" value = "b" url = f"/app/?filter[value]={value}" query_params = self.mocked_query_params(url, OCPTagView) # the mocked query parameters dont include the key from the url so it needs to be added query_params.kwargs = {"key": key} handler = OCPTagQueryHandler(query_params) access = ["my-ocp-cluster-2"] filt = [ { "field": "report_period__cluster_id", "operation": "icontains", "composition_key": "cluster_filter" }, { "field": "report_period__cluster_alias", "operation": "icontains", "composition_key": "cluster_filter" }, ] filters = QueryFilterCollection() handler.set_access_filters(access, filt, filters) expected = [] expected.append( QueryFilter(field="report_period__cluster_id", operation="icontains", parameter=["my-ocp-cluster-2"])) expected.append( QueryFilter(field="report_period__cluster_alias", operation="icontains", parameter=["my-ocp-cluster-2"])) self.assertEqual(filters._filters, expected)
def test_set_operator_specified_tag_filters_or(self): """Test that AND/OR terms are correctly applied to tag filters.""" operator = "or" term = self.mock_tag_key first = FAKE.word() second = FAKE.word() operation = "icontains" url = ( f"?filter[time_scope_value]=-1&" f"filter[or:tag:{term}]={first}&" f"filter[or:tag:{term}]={second}&" f"group_by[or:tag:{term}]={first}&" f"group_by[or:tag:{term}]={second}" ) params = self.mocked_query_params(url, self.mock_view) mapper = {"filter": [{}], "filters": {term: {"field": term, "operation": operation}}} rqh = create_test_handler(params, mapper=mapper) output = rqh._set_operator_specified_tag_filters(QueryFilterCollection(), operator) self.assertIsNotNone(output) expected = QueryFilterCollection( filters=[ QueryFilter(field=term, operation=operation, parameter=second, logical_operator=operator), QueryFilter(field=term, operation=operation, parameter=first, logical_operator=operator), ] ) self.assertIsInstance(output, QueryFilterCollection) assertSameQ(output.compose(), expected.compose())
def _set_tag_filters(self, filters): """Create tag_filters.""" tag_column = self._mapper.tag_column tag_filters = self.get_tag_filter_keys() tag_group_by = self.get_tag_group_by_keys() tag_filters.extend(tag_group_by) tag_filters = [ tag for tag in tag_filters if 'and:' not in tag and 'or:' not in tag ] for tag in tag_filters: # Update the filter to use the label column name tag_db_name = tag_column + '__' + strip_tag_prefix(tag) filt = {'field': tag_db_name, 'operation': 'icontains'} group_by = self.parameters.get_group_by(tag, list()) filter_ = self.parameters.get_filter(tag, list()) list_ = list(set(group_by + filter_)) # uniquify the list if list_ and not ReportQueryHandler.has_wildcard(list_): for item in list_: q_filter = QueryFilter(parameter=item, **filt) filters.add(q_filter) elif list_ and ReportQueryHandler.has_wildcard(list_): wild_card_filt = {'field': tag_column, 'operation': 'has_key'} q_filter = QueryFilter(parameter=strip_tag_prefix(tag), **wild_card_filt) filters.add(q_filter) return filters
def test_set_access_filter_with_list(self): """ Tests that when an access restriction, filters, and a filter list are passed in, the correct query filters are added """ # create the elements needed to mock the query handler term = self.mock_tag_key operation = "icontains" params = self.mocked_query_params("", self.mock_view) mapper = {"filter": [{}], "filters": {term: {"field": term, "operation": operation}}} rqh = create_test_handler(params, mapper=mapper) # set filters and access to be used in function filters = QueryFilterCollection() access = ["589173575009"] filt = [ {"field": "account_alias__account_alias", "operation": "icontains", "composition_key": "account_filter"}, {"field": "usage_account_id", "operation": "icontains", "composition_key": "account_filter"}, ] expected = QueryFilterCollection( filters=[ QueryFilter(field="account_alias__account_alias", operation="in", composition_key="account_filter"), QueryFilter(field="usage_account_id", operation="in", composition_key="account_filter"), ] ) rqh._set_access_filters(access, filt, filters) self.assertIsInstance(filters, QueryFilterCollection) assertSameQ(filters.compose(), expected.compose())
def test_execute_query_current_month_filter_service(self): """Test execute_query for current month on monthly filtered by service.""" self.generator = OCPAzureReportDataGenerator(self.tenant, self.provider, current_month_only=True) self.generator.add_data_to_tenant( fixed_fields=["subscription_guid", "resource_location", "tags", "service_name"] ) service = self.generator.config.service_name url = f"?filter[time_scope_units]=month&filter[time_scope_value]=-1&filter[resolution]=monthly&filter[service_name]={service}" # noqa: E501 query_params = self.mocked_query_params(url, OCPAzureCostView) handler = OCPAzureReportQueryHandler(query_params) query_output = handler.execute_query() data = query_output.get("data") self.assertIsNotNone(data) self.assertIsNotNone(query_output.get("total")) total = query_output.get("total") aggregates = handler._mapper.report_type_map.get("aggregates") filters = {**self.this_month_filter, "service_name__icontains": service} for filt in handler._mapper.report_type_map.get("filter"): if filt: qf = QueryFilter(**filt) filters.update({qf.composed_query_string(): qf.parameter}) current_totals = self.get_totals_by_time_scope(aggregates, filters) self.assertIsNotNone(total.get("cost")) self.assertEqual(total.get("cost", {}).get("value", 0), current_totals.get("cost", 1)) cmonth_str = self.dh.this_month_start.strftime("%Y-%m") for data_item in data: month_val = data_item.get("date", "not-a-date") month_data = data_item.get("values") self.assertEqual(month_val, cmonth_str) self.assertIsInstance(month_data, list)
def _get_sub_ou_list(self, data, org_ids): """Get a list of the sub org units for a org unit.""" level = data.get("level") level = level + 1 unit_path = data.get("org_unit_path") final_sub_ou_list = [] with tenant_context(self.tenant): for source in self.data_sources: # Grab columns for this query account_info = source.get("account_alias_column") level_column = source.get("level_column") org_path = source.get("org_path_column") # Build filters filters = QueryFilterCollection() no_accounts = QueryFilter(field=f"{account_info}", operation="isnull", parameter=True) filters.add(no_accounts) exact_parent_id = QueryFilter(field=f"{level_column}", operation="exact", parameter=level) filters.add(exact_parent_id) path_on_like = QueryFilter(field=f"{org_path}", operation="icontains", parameter=unit_path) filters.add(path_on_like) composed_filters = filters.compose() # Start quering sub_org_query = source.get("db_table").objects sub_org_query = sub_org_query.filter(composed_filters) sub_org_query = sub_org_query.filter(id__in=org_ids) sub_ou_list = sub_org_query.values_list("org_unit_id", flat=True) final_sub_ou_list.extend(sub_ou_list) return final_sub_ou_list
def _get_filter(self, delta=False): """Create dictionary for filter parameters. Args: delta (Boolean): Construct timeframe for delta Returns: (Dict): query filter dictionary """ filters = QueryFilterCollection() # add time constraint filters if delta: date_delta = self._get_date_delta() start = self.start_datetime - date_delta end = self.end_datetime - date_delta else: start = self.start_datetime end = self.end_datetime start_filter = QueryFilter(field='usage_start__date', operation='gte', parameter=start) end_filter = QueryFilter(field='usage_end__date', operation='lte', parameter=end) filters.add(query_filter=start_filter) filters.add(query_filter=end_filter) return filters
def test_execute_query_by_filtered_cluster(self): """Test execute_query monthly breakdown by filtered cluster.""" self.generator.add_data_to_tenant() cluster = self.generator.cluster_id url = f"?filter[time_scope_units]=month&filter[time_scope_value]=-1&filter[resolution]=monthly&group_by[cluster]={cluster}" # noqa: E501 query_params = self.mocked_query_params(url, OCPAzureCostView) handler = OCPAzureReportQueryHandler(query_params) query_output = handler.execute_query() data = query_output.get("data") self.assertIsNotNone(data) self.assertIsNotNone(query_output.get("total")) total = query_output.get("total") aggregates = handler._mapper.report_type_map.get("aggregates") filters = {**self.this_month_filter, "cluster_id__icontains": cluster} for filt in handler._mapper.report_type_map.get("filter"): if filt: qf = QueryFilter(**filt) filters.update({qf.composed_query_string(): qf.parameter}) current_totals = self.get_totals_by_time_scope(aggregates, filters) self.assertIsNotNone(total.get("cost")) self.assertEqual(total.get("cost", {}).get("value", 0), current_totals.get("cost", 1)) cmonth_str = self.dh.this_month_start.strftime("%Y-%m") for data_item in data: month_val = data_item.get("date", "not-a-date") month_data = data_item.get("clusters") self.assertEqual(month_val, cmonth_str) self.assertIsInstance(month_data, list) for month_item in month_data: self.assertIsInstance(month_item.get("cluster"), str) self.assertIsInstance(month_item.get("values"), list) self.assertIsNotNone(month_item.get("values")[0].get("cost"))
def _get_time_based_filters(self, delta=False): """Overridden from QueryHandler.""" start_filter = QueryFilter(field='usage_start', operation='gte', parameter=self.start_datetime) end_filter = QueryFilter(field='usage_start', operation='lte', parameter=self.end_datetime) return start_filter, end_filter
def _get_search_filter(self, filters): """Populate the query filter collection for search filters. Args: filters (QueryFilterCollection): collection of query filters Returns: (QueryFilterCollection): populated collection of query filters """ # define filter parameters using API query params. fields = self._mapper._provider_map.get('filters') for q_param, filt in fields.items(): group_by = self.get_query_param_data('group_by', q_param, list()) filter_ = self.get_query_param_data('filter', q_param, list()) list_ = list(set(group_by + filter_)) # uniquify the list if list_ and not ReportQueryHandler.has_wildcard(list_): if isinstance(filt, list): for _filt in filt: for item in list_: q_filter = QueryFilter(parameter=item, **_filt) filters.add(q_filter) else: for item in list_: q_filter = QueryFilter(parameter=item, **filt) filters.add(q_filter) # Update filters with tag filters filters = self._set_tag_filters(filters) composed_filters = filters.compose() LOG.debug(f'_get_search_filter: {composed_filters}') return composed_filters
def test_set_access_filter_with_list(self): """ Tests that when an access restriction, filters, and a filter list are passed in, the correct query filters are added """ # create the elements needed to mock the query handler params = self.mocked_query_params("", AWSCostForecastView) instance = AWSForecast(params) # set filters and access to be used in function filters = QueryFilterCollection() access = ["589173575009"] filt = [ { "field": "account_alias__account_alias", "operation": "icontains", "composition_key": "account_filter" }, { "field": "usage_account_id", "operation": "icontains", "composition_key": "account_filter" }, ] expected = QueryFilterCollection(filters=[ QueryFilter(field="account_alias__account_alias", operation="in", composition_key="account_filter"), QueryFilter(field="usage_account_id", operation="in", composition_key="account_filter"), ]) instance.set_access_filters(access, filt, filters) self.assertIsInstance(filters, QueryFilterCollection) assertSameQ(filters.compose(), expected.compose())
def _get_filter(self, delta=False): """Create dictionary for filter parameters. Args: delta (Boolean): Construct timeframe for delta Returns: (Dict): query filter dictionary """ filters = super()._get_filter(delta) for filter_key in SUPPORTED_FILTERS: filter_value = self.get_query_param_data('filter', filter_key) if filter_value and not TagQueryHandler.has_wildcard(filter_value): filter_obj = FILTER_MAP.get(filter_key) if isinstance(filter_obj, list): for _filt in filter_obj: for item in filter_value: q_filter = QueryFilter(parameter=item, **_filt) filters.add(q_filter) else: for item in filter_value: q_filter = QueryFilter(parameter=item, **filter_obj) filters.add(q_filter) # Update filters that specifiy and or or in the query parameter and_composed_filters = self._set_operator_specified_filters('and') or_composed_filters = self._set_operator_specified_filters('or') composed_filters = filters.compose() composed_filters = composed_filters & and_composed_filters & or_composed_filters LOG.debug(f'_get_filter: {composed_filters}') return composed_filters
def test_composed_string_table_op(self): """Test composed_query_string() method using table and operation parameters.""" table = self.fake.word() operation = self.fake.word() filt = QueryFilter(table=table, operation=operation) expected = f'{table}__{operation}' self.assertEqual(filt.composed_query_string(), expected)
def test_composed_string_all(self): """Test composed_query_string() method using all parameters.""" table = self.fake.word() field = self.fake.word() operation = self.fake.word() parameter = self.fake.word() filt = QueryFilter(table, field, operation, parameter) expected = f'{table}__{field}__{operation}' self.assertEqual(filt.composed_query_string(), expected)
def _set_operator_specified_filters(self, operator): """Set any filters using AND instead of OR.""" fields = self._mapper._provider_map.get("filters") filters = QueryFilterCollection() composed_filter = Q() for q_param, filt in fields.items(): q_param = operator + ":" + q_param group_by = self.parameters.get_group_by(q_param, list()) filter_ = self.parameters.get_filter(q_param, list()) list_ = list(set(group_by + filter_)) # uniquify the list logical_operator = operator # This is a flexibilty feature allowing a user to set # a single and: value and still get a result instead # of erroring on validation if len(list_) < 2: logical_operator = "or" if list_ and not ReportQueryHandler.has_wildcard(list_): if isinstance(filt, list): for _filt in filt: filt_filters = QueryFilterCollection() for item in list_: q_filter = QueryFilter( parameter=item, logical_operator=logical_operator, **_filt) filt_filters.add(q_filter) # List filter are a complex mix of and/or logic # Each filter in the list must be ORed together # regardless of the operator on the item in the filter # Ex: # (OR: # (AND: # ('cluster_alias__icontains', 'ni'), # ('cluster_alias__icontains', 'se') # ), # (AND: # ('cluster_id__icontains', 'ni'), # ('cluster_id__icontains', 'se') # ) # ) composed_filter = composed_filter | filt_filters.compose( ) else: list_ = self._build_custom_filter_list( q_param, filt.get("custom"), list_) for item in list_: q_filter = QueryFilter( parameter=item, logical_operator=logical_operator, **filt) filters.add(q_filter) if filters: composed_filter = composed_filter & filters.compose() return composed_filter
def test_composed_dict_field(self): """Test composed_dict() method without a Table parameter.""" field = self.fake.word() operation = self.fake.word() parameter = self.fake.word() filt = QueryFilter(field=field, operation=operation, parameter=parameter) expected_dict = {f'{field}__{operation}': parameter} expected = Q(**expected_dict) self.assertEqual(filt.composed_Q(), expected)
def test_contains_fail(self): """Test the __contains__() method fails with a non-matching filter.""" qf1 = QueryFilter(table=self.fake.word(), field=self.fake.word(), parameter=self.fake.word()) qf2 = QueryFilter(table=self.fake.word(), field=self.fake.word(), parameter=self.fake.word()) qf_coll = QueryFilterCollection([qf1]) self.assertNotIn(qf2, qf_coll) self.assertFalse(qf2 in qf_coll)
def test_iterable(self): """Test the __iter__() method returns an iterable.""" qf1 = QueryFilter(table=self.fake.word(), field=self.fake.word(), parameter=self.fake.word()) qf2 = QueryFilter(table=self.fake.word(), field=self.fake.word(), parameter=self.fake.word()) qf_coll = QueryFilterCollection([qf1, qf2]) self.assertIsInstance(qf_coll.__iter__(), Iterable)
def test_composed_dict_all(self): """Test composed_dict() method with all parameters.""" table = self.fake.word() field = self.fake.word() operation = self.fake.word() parameter = self.fake.word() filt = QueryFilter(table, field, operation, parameter) expected_dict = {f'{table}__{field}__{operation}': parameter} expected = Q(**expected_dict) self.assertEqual(filt.composed_Q(), expected)
def test_from_string_two_parts(self): """Test from_string() method with two parts.""" table = self.fake.word() operation = self.fake.word() SEP = QueryFilter.SEP test_string = table + SEP + operation filt = QueryFilter().from_string(test_string) self.assertEqual(filt.table, table) self.assertEqual(filt.operation, operation) self.assertEqual(filt.composed_query_string(), test_string)
def _get_time_based_filters(self, delta=False): if delta: date_delta = self._get_date_delta() start = self.start_datetime - date_delta end = self.end_datetime - date_delta else: start = self.start_datetime end = self.end_datetime start_filter = QueryFilter(field="usage_start", operation="gte", parameter=start.date()) end_filter = QueryFilter(field="usage_end", operation="lte", parameter=end.date()) return start_filter, end_filter
def test_delete_filter(self): """Test the delete() method works with QueryFilters.""" qf1 = QueryFilter(table=self.fake.word(), field=self.fake.word(), parameter=self.fake.word()) qf2 = QueryFilter(table=self.fake.word(), field=self.fake.word(), parameter=self.fake.word()) qf_coll = QueryFilterCollection([qf1, qf2]) qf_coll.delete(qf1) self.assertEqual([qf2], qf_coll._filters) self.assertNotIn(qf1, qf_coll)
def _get_search_filter(self, filters): """Populate the query filter collection for search filters. Args: filters (QueryFilterCollection): collection of query filters Returns: (QueryFilterCollection): populated collection of query filters """ # define filter parameters using API query params. fields = self._mapper._provider_map.get("filters") access_filters = QueryFilterCollection() for q_param, filt in fields.items(): access = self.parameters.get_access(q_param, list()) group_by = self.parameters.get_group_by(q_param, list()) filter_ = self.parameters.get_filter(q_param, list()) list_ = list(set(group_by + filter_)) # uniquify the list if list_ and not ReportQueryHandler.has_wildcard(list_): if isinstance(filt, list): for _filt in filt: for item in list_: q_filter = QueryFilter(parameter=item, **_filt) filters.add(q_filter) else: list_ = self._build_custom_filter_list( q_param, filt.get("custom"), list_) for item in list_: q_filter = QueryFilter(parameter=item, **filt) filters.add(q_filter) if access: access_filt = copy.deepcopy(filt) self.set_access_filters(access, access_filt, access_filters) # Update filters with tag filters filters = self._set_tag_filters(filters) filters = self._set_operator_specified_tag_filters(filters, "and") filters = self._set_operator_specified_tag_filters(filters, "or") # Update filters that specifiy and or or in the query parameter and_composed_filters = self._set_operator_specified_filters("and") or_composed_filters = self._set_operator_specified_filters("or") multi_field_or_composed_filters = self._set_or_filters() composed_filters = filters.compose() composed_filters = composed_filters & and_composed_filters & or_composed_filters if access_filters: composed_access_filters = access_filters.compose() composed_filters = composed_filters & composed_access_filters if multi_field_or_composed_filters: composed_filters = composed_filters & multi_field_or_composed_filters LOG.debug(f"_get_search_filter: {composed_filters}") return composed_filters
def test_indexing(self): """Test that __getitem__() allows array slicing.""" qf1 = QueryFilter(table=self.fake.word(), field=self.fake.word(), parameter=self.fake.word()) qf2 = QueryFilter(table=self.fake.word(), field=self.fake.word(), parameter=self.fake.word()) qf_coll = QueryFilterCollection([qf1, qf2]) self.assertEqual(qf_coll[0], qf1) self.assertEqual(qf_coll[1], qf2) self.assertEqual(qf_coll[-1], qf2) self.assertEqual(qf_coll[-2], qf1)
def _get_time_based_filters(self, delta=False): if delta: date_delta = self._get_date_delta() start = self.start_datetime - date_delta end = self.end_datetime - date_delta else: start = self.start_datetime end = self.end_datetime start_filter = QueryFilter(field='usage_start__date', operation='gte', parameter=start) end_filter = QueryFilter(field='usage_end__date', operation='lte', parameter=end) return start_filter, end_filter
def _get_filter(self, delta=False): # noqa: C901 """Create dictionary for filter parameters. Args: delta (Boolean): Construct timeframe for delta Returns: (Dict): query filter dictionary """ filters = QueryFilterCollection() if not self.parameters.get_filter("value"): for source in self.data_sources: start_filter, end_filter = self._get_time_based_filters( source, delta) filters.add(query_filter=start_filter) filters.add(query_filter=end_filter) for filter_key in self.SUPPORTED_FILTERS: if self.parameters.get_filter("value") and filter_key == "enabled": continue filter_value = self.parameters.get_filter(filter_key) if filter_value and not TagQueryHandler.has_wildcard(filter_value): filter_obj = self.FILTER_MAP.get(filter_key) if isinstance(filter_value, bool): filters.add(QueryFilter(**filter_obj)) elif isinstance(filter_obj, list): for _filt in filter_obj: for item in filter_value: q_filter = QueryFilter(parameter=item, **_filt) filters.add(q_filter) else: for item in filter_value: q_filter = QueryFilter(parameter=item, **filter_obj) filters.add(q_filter) access = self.parameters.get_access(filter_key) filt = self.FILTER_MAP.get(filter_key, []) if access and filt: filt = self.FILTER_MAP.get(filter_key) q_filter = QueryFilter(parameter=access, **filt) filters.add(q_filter) # Update filters that specifiy and or or in the query parameter and_composed_filters = self._set_operator_specified_filters("and") or_composed_filters = self._set_operator_specified_filters("or") composed_filters = filters.compose() composed_filters = composed_filters & and_composed_filters & or_composed_filters LOG.debug(f"_get_filter: {composed_filters}") return composed_filters
def set_access_filters(self, access, filt, filters): """ Sets the access filters to ensure RBAC restrictions given the users access, the current filter and the filter collection Args: access (list) the list containing the users relevant access filt (list or dict) contains the filters that need filters (QueryFilterCollection) the filter collection to add the new filters to returns: None """ for _filt in filt if isinstance(filt, list) else [filt]: check_field_type = None try: if hasattr(self, "query_table"): # Reports APIs check_field_type = self.query_table._meta.get_field( _filt.get("field", "")).get_internal_type() elif hasattr(self, "data_sources"): # Tags APIs check_field_type = ( self.data_sources[0].get("db_table")._meta.get_field( _filt.get("field", "")).get_internal_type()) except FieldDoesNotExist: pass _filt[ "operation"] = "contains" if check_field_type == "ArrayField" else "in" q_filter = QueryFilter(parameter=access, **_filt) filters.add(q_filter)
def _create_accounts_mapping(self): """Returns a mapping of org ids to accounts.""" account_mapping = {} with tenant_context(self.tenant): for source in self.data_sources: # Grab columns for this query account_info = source.get("account_alias_column") # Create filters & Query filters = QueryFilterCollection() no_org_units = QueryFilter(field=f"{account_info}", operation="isnull", parameter=False) filters.add(no_org_units) composed_filters = filters.compose() account_query = source.get("db_table").objects account_query = account_query.filter(composed_filters) account_query = account_query.exclude(deleted_timestamp__lte=self.start_datetime) account_query = account_query.exclude(created_timestamp__gt=self.end_datetime) if self.access: accounts_to_filter = self.access.get("aws.account", {}).get("read", []) if accounts_to_filter and "*" not in accounts_to_filter: account_query = account_query.filter(account_alias__account_id__in=accounts_to_filter) account_query = account_query.order_by(f"{account_info}", "-created_timestamp") account_query = account_query.distinct(f"{account_info}") account_query = account_query.annotate( alias=Coalesce(F(f"{account_info}__account_alias"), F(f"{account_info}__account_id")) ) for account in account_query: org_id = account.org_unit_id alias = account.alias if account_mapping.get(org_id): account_list = account_mapping[org_id] account_list.append(alias) account_mapping[org_id] = account_list else: account_mapping[org_id] = [alias] return account_mapping
def _get_filter(self, delta=False): # noqa: C901 """Create dictionary for filter parameters. Args: delta (Boolean): Construct timeframe for delta Returns: (Dict): query filter dictionary """ filters = QueryFilterCollection() for filter_key in self.SUPPORTED_FILTERS: filter_value = self.parameters.get_filter(filter_key) if filter_value and not OrgQueryHandler.has_wildcard(filter_value): filter_obj = self.FILTER_MAP.get(filter_key) for item in filter_value: q_filter = QueryFilter(parameter=item, **filter_obj) filters.add(q_filter) # Update filters that specifiy and or or in the query parameter and_composed_filters = self._set_operator_specified_filters("and") or_composed_filters = self._set_operator_specified_filters("or") composed_filters = filters.compose() filter_list = [composed_filters, and_composed_filters, or_composed_filters] final_filters = None for filter_option in filter_list: if filter_option: if final_filters is not None: final_filters & filter_option else: final_filters = filter_option LOG.debug(f"_get_filter: {final_filters}") return final_filters