Newer Version Available

This content describes an older version of this product. View Latest

Compound Filters in the Apex Connector Framework

Filters can have child filters, which are stored in the subfilters property.

If a filter has children, the filter type must be one of the following.

Filter Type Description
AND_ We return all rows that match all of the subfilters.
OR_ We return all rows that match any of the subfilters.
NOT_ The filter reverses how its child filter evaluates rows. Filters of this type can have only one subfilter.

This code example illustrates how to deal with compound filters.

1override global DataSource.TableResult query(DataSource.QueryContext context) {
2    // Call out to an external data source and retrieve a set of records.
3    // We should attempt to get as much information as possible about the 
4    // query from the QueryContext, to minimize the number of records 
5    // that we return.
6    List<Map<String,Object>> rows = retrieveData(context);
7    
8    // This only filters the results. Anything in the query that we don’t 
9    // currently support, such as aggregation or sorting, is ignored.
10    return DataSource.TableResult.get(context, postFilterRecords(
11        context.tableSelection.filter, rows));
12}
13
14private List<Map<String,Object>> retrieveData(DataSource.QueryContext context) {
15    // Call out to an external data source. Form the callout so that
16    // it filters as much as possible on the remote site,
17    // based on the parameters in the QueryContext.
18    return ...;
19}
20
21private List<Map<String,Object>> postFilterRecords(
22    DataSource.Filter filter, List<Map<String,Object>> rows) {
23    if (filter == null) {
24        return rows;
25    }
26    DataSource.FilterType type = filter.type;
27    List<Map<String,Object>> retainedRows = new List<Map<String,Object>>();
28    if (type == DataSource.FilterType.NOT_) {
29        // We expect one Filter in the subfilters.
30        DataSource.Filter subfilter = filter.subfilters.get(0);
31        for (Map<String,Object> row : rows) {
32            if (!evaluate(filter, row)) {
33                retainedRows.add(row);
34            }
35        }
36        return retainedRows;
37    } else if (type == DataSource.FilterType.AND_) {
38        // For each filter, find all matches; anything that matches ALL filters 
39        // is returned.
40        retainedRows = rows;
41        for (DataSource.Filter subfilter : filter.subfilters) {
42            retainedRows = postFilterRecords(subfilter, retainedRows);
43        }
44        return retainedRows;
45    } else if (type == DataSource.FilterType.OR_) {
46        // For each filter, find all matches. Anything that matches 
47        // at least one filter is returned.
48        for (DataSource.Filter subfilter : filter.subfilters) {
49            List<Map<String,Object>> matchedRows = postFilterRecords(
50                subfilter, rows);
51            retainedRows.addAll(matchedRows);
52        }
53        return retainedRows;
54    } else {
55        // Find all matches for this filter in our collection of records.
56        for (Map<String,Object> row : rows) {
57            if (evaluate(filter, row)) {
58                retainedRows.add(row);
59            }
60        }
61        return retainedRows;
62    }
63}
64
65private Boolean evaluate(DataSource.Filter filter, Map<String,Object> row) {
66    if (filter.type == DataSource.FilterType.EQUALS) {
67        String columnName = filter.columnName;
68        Object expectedValue = filter.columnValue;
69        Object foundValue = row.get(columnName);
70        return expectedValue.equals(foundValue);
71    } else {
72        // Throw an exception; implementing other filter types is left
73        // as an exercise for the reader.
74        throwException('Unexpected filter type: ' + filter.type);
75    }
76    return false;
77}