-add feature to filter on test attributes in TKO
-new server arguments "include_attributes_where" and "exclude_attributes_where" for filtering on test attributes
-refactor joining code in TKO models.py to support test attributes joining
-add new UI to CommonPanel.java to filter on test attributes. some of the UI code was written in a general way so that in the future it could be merged with some of the graphing UI code.
-modified TestSets and code that uses them to fix two bugs - first, TestSets didn't contain all the relevant filtering information (only the SQL clause), and second, the SQL clause would build up incorrectly during drilldown
git-svn-id: http://test.kernel.org/svn/autotest/trunk@2177 592f7852-d20e-0410-864c-8624ca9c26a4
diff --git a/frontend/client/src/autotest/common/Utils.java b/frontend/client/src/autotest/common/Utils.java
index 1997635..7583f1c 100644
--- a/frontend/client/src/autotest/common/Utils.java
+++ b/frontend/client/src/autotest/common/Utils.java
@@ -103,14 +103,19 @@
}
public static <T> String joinStrings(String joiner, List<T> objects) {
- if (objects.size() == 0) {
- return "";
- }
-
- StringBuilder result = new StringBuilder(objects.get(0).toString());
- for (int i = 1; i < objects.size(); i++) {
- result.append(joiner);
- result.append(objects.get(i).toString());
+ StringBuilder result = new StringBuilder();
+ boolean first = true;
+ for (T object : objects) {
+ String piece = object.toString();
+ if (piece.equals("")) {
+ continue;
+ }
+ if (first) {
+ first = false;
+ } else {
+ result.append(joiner);
+ }
+ result.append(piece);
}
return result.toString();
}
diff --git a/frontend/client/src/autotest/tko/CommonPanel.java b/frontend/client/src/autotest/tko/CommonPanel.java
index ca7b42f..b1bfc34 100644
--- a/frontend/client/src/autotest/tko/CommonPanel.java
+++ b/frontend/client/src/autotest/tko/CommonPanel.java
@@ -4,6 +4,7 @@
import autotest.common.ui.ElementWidget;
import autotest.common.ui.SimpleHyperlink;
import autotest.tko.TkoUtils.FieldInfo;
+import autotest.tko.WidgetList.ListWidgetFactory;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONString;
@@ -11,14 +12,20 @@
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlexTable;
+import com.google.gwt.user.client.ui.HTML;
+import com.google.gwt.user.client.ui.HorizontalPanel;
+import com.google.gwt.user.client.ui.Label;
+import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.TextArea;
+import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.user.client.ui.PopupPanel.PositionCallback;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
@@ -26,21 +33,80 @@
import java.util.Set;
class CommonPanel extends Composite implements ClickListener, PositionCallback {
+ private static final String WIKI_URL = "http://autotest.kernel.org/wiki/TkoHowTo";
private static final String SHOW_QUICK_REFERENCE = "Show quick reference";
private static final String HIDE_QUICK_REFERENCE = "Hide quick reference";
private static final String SHOW_CONTROLS = "Show controls";
private static final String HIDE_CONTROLS = "Hide controls";
+ private static final String INCLUDE_ATTRIBUTES_TABLE = "test_attributes_include";
+ private static final String EXCLUDE_ATTRIBUTES_TABLE = "test_attributes_exclude";
private static CommonPanel theInstance = new CommonPanel();
+ private class AttributeFilter extends Composite implements ClickListener {
+ private ListBox includeOrExclude = new ListBox();
+ private TextBox attributeWhere = new TextBox(), valueWhere = new TextBox();
+
+ public AttributeFilter() {
+ includeOrExclude.addItem("Include");
+ includeOrExclude.addItem("Exclude");
+
+ Panel panel = new HorizontalPanel();
+ panel.add(includeOrExclude);
+ panel.add(new Label("tests with attribute"));
+ panel.add(attributeWhere);
+ panel.add(new Label("and value"));
+ panel.add(valueWhere);
+
+ SimpleHyperlink deleteLink = new SimpleHyperlink("[X]");
+ deleteLink.addClickListener(this);
+ panel.add(deleteLink);
+
+ initWidget(panel);
+ }
+
+ public void onClick(Widget sender) {
+ attributeFilterList.deleteWidget(this);
+ }
+
+ public boolean isInclude() {
+ return includeOrExclude.getSelectedIndex() == 0;
+ }
+
+ public String getFilterString() {
+ String tableName;
+ if (isInclude()) {
+ tableName = INCLUDE_ATTRIBUTES_TABLE;
+ } else {
+ tableName = EXCLUDE_ATTRIBUTES_TABLE;
+ }
+
+ return "(" + tableName + ".attribute " + attributeWhere.getText() + " AND " +
+ tableName + ".value " + valueWhere.getText() + ")";
+ }
+
+ public void addToHistory(Map<String, String> args, String prefix) {
+ args.put(prefix + "_include", Boolean.toString(isInclude()));
+ args.put(prefix + "_attribute", attributeWhere.getText());
+ args.put(prefix + "_value", valueWhere.getText());
+ }
+ }
+
+ private class AttributeFilterFactory implements ListWidgetFactory<AttributeFilter> {
+ public AttributeFilter getNewWidget() {
+ return new AttributeFilter();
+ }
+ }
+
private TextArea customSqlBox = new TextArea();
private CheckBox showInvalid = new CheckBox("Show invalidated tests");
private SimpleHyperlink quickReferenceLink = new SimpleHyperlink(SHOW_QUICK_REFERENCE);
private PopupPanel quickReferencePopup;
private SimpleHyperlink showHideControlsLink = new SimpleHyperlink(HIDE_CONTROLS);
private Panel allControlsPanel = RootPanel.get("common_all_controls");
- private String currentCondition = "";
- private boolean currentShowInvalid = false;
+ private boolean savedShowInvalid = false;
+ private JSONObject savedCondition = new JSONObject();
private Set<CommonPanelListener> listeners = new HashSet<CommonPanelListener>();
+ private WidgetList<AttributeFilter> attributeFilterList;
public static interface CommonPanelListener {
public void onSetControlsVisible(boolean visible);
@@ -56,8 +122,20 @@
quickReferenceLink.addClickListener(this);
showHideControlsLink.addClickListener(this);
+ attributeFilterList =
+ new WidgetList<AttributeFilter>(new AttributeFilterFactory(), "Add attribute filter");
+ Panel titlePanel = new HorizontalPanel();
+ titlePanel.add(getFieldLabel("Test attributes:"));
+ titlePanel.add(new HTML(" <a href=\"" + WIKI_URL + "#attribute_filtering\" " +
+ "target=\"_blank\">[?]</a>"));
+ Panel attributeFilters = new VerticalPanel();
+ attributeFilters.setStyleName("box");
+ attributeFilters.add(titlePanel);
+ attributeFilters.add(attributeFilterList);
+
Panel commonFilterPanel = new VerticalPanel();
commonFilterPanel.add(customSqlBox);
+ commonFilterPanel.add(attributeFilters);
commonFilterPanel.add(showInvalid);
RootPanel.get("common_filters").add(commonFilterPanel);
RootPanel.get("common_quick_reference").add(quickReferenceLink);
@@ -65,6 +143,12 @@
generateQuickReferencePopup();
}
+ private Widget getFieldLabel(String string) {
+ Label label = new Label(string);
+ label.setStyleName("field-name");
+ return label;
+ }
+
public static CommonPanel getPanel() {
return theInstance;
}
@@ -84,44 +168,106 @@
return customSqlBox.getText().trim();
}
- private void setSqlCondition(String text) {
+ public void setSqlCondition(String text) {
customSqlBox.setText(text);
saveSqlCondition();
}
- public void saveSqlCondition() {
- currentCondition = getSqlCondition();
- currentShowInvalid = showInvalid.isChecked();
+ private void saveAttributeFilters() {
+ List<String> include = new ArrayList<String>(), exclude = new ArrayList<String>();
+ for (AttributeFilter filter : attributeFilterList.getWidgets()) {
+ if (filter.isInclude()) {
+ include.add(filter.getFilterString());
+ } else {
+ exclude.add(filter.getFilterString());
+ }
+ }
+
+ String includeSql = Utils.joinStrings(" OR ", include);
+ String excludeSql = Utils.joinStrings(" OR ", exclude);
+ saveIfNonempty("include_attributes_where", includeSql);
+ saveIfNonempty("exclude_attributes_where", excludeSql);
}
- public JSONObject getSavedConditionArgs() {
- JSONObject args = new JSONObject();
- args.put("extra_where", new JSONString(currentCondition));
- if (!currentShowInvalid) {
- List<String> labelsToExclude = Arrays.asList(new String[] {"invalidated"});
- args.put("exclude_labels", Utils.stringsToJSON(labelsToExclude));
+ public void saveSqlCondition() {
+ savedCondition = new JSONObject();
+ saveIfNonempty("extra_where", getSqlCondition());
+ saveAttributeFilters();
+
+ savedShowInvalid = showInvalid.isChecked();
+ if (!savedShowInvalid) {
+ List<String> labelsToExclude =
+ Arrays.asList(new String[] {TestLabelManager.INVALIDATED_LABEL});
+ savedCondition.put("exclude_labels", Utils.stringsToJSON(labelsToExclude));
}
- return args;
+ }
+
+ private void saveIfNonempty(String key, String value) {
+ if (value.equals("")) {
+ return;
+ }
+ savedCondition.put(key, new JSONString(value));
}
- public void setCondition(TestSet tests) {
- setSqlCondition(tests.getCondition());
+ public JSONObject getSavedConditionArgs() {
+ return Utils.copyJSONObject(savedCondition);
+ }
+
+ public void refineCondition(TestSet tests) {
+ String sqlCondition = TkoUtils.getSqlCondition(savedCondition);
+ String newCondition = tests.getPartialSqlCondition();
+ setSqlCondition(TkoUtils.joinWithParens(" AND ", sqlCondition, newCondition));
+ }
+
+ private String getListKey(String base, int index) {
+ return base + "_" + Integer.toString(index);
+ }
+
+ public AttributeFilter attributeFilterFromHistory(Map<String, String> args, String prefix) {
+ String includeKey = prefix + "_include";
+ if (!args.containsKey(includeKey)) {
+ return null;
+ }
+
+ AttributeFilter filter = new AttributeFilter();
+ boolean include = Boolean.valueOf(args.get(includeKey));
+ filter.includeOrExclude.setSelectedIndex(include ? 0 : 1);
+ filter.attributeWhere.setText(args.get(prefix + "_attribute"));
+ filter.valueWhere.setText(args.get(prefix + "_value"));
+ return filter;
}
public void handleHistoryArguments(Map<String, String> arguments) {
setSqlCondition(arguments.get("condition"));
- currentShowInvalid = Boolean.valueOf(arguments.get("show_invalid"));
- showInvalid.setChecked(currentShowInvalid);
+ savedShowInvalid = Boolean.valueOf(arguments.get("show_invalid"));
+ showInvalid.setChecked(savedShowInvalid);
+
+ attributeFilterList.clear();
+ for (int index = 0; ; index++) {
+ AttributeFilter filter = attributeFilterFromHistory(arguments,
+ getListKey("attribute", index));
+ if (filter == null) {
+ break;
+ }
+ attributeFilterList.addWidget(filter);
+ }
}
public void addHistoryArguments(Map<String, String> arguments) {
- arguments.put("condition", currentCondition);
- arguments.put("show_invalid", Boolean.toString(currentShowInvalid));
+ if (savedCondition.containsKey("extra_where")) {
+ arguments.put("condition", savedCondition.get("extra_where").isString().stringValue());
+ }
+ arguments.put("show_invalid", Boolean.toString(savedShowInvalid));
+ int index = 0;
+ for (AttributeFilter filter : attributeFilterList.getWidgets()) {
+ filter.addToHistory(arguments, getListKey("attribute", index));
+ index++;
+ }
}
public void fillDefaultHistoryValues(Map<String, String> arguments) {
Utils.setDefaultValue(arguments, "condition", "");
- Utils.setDefaultValue(arguments, "show_invalid", Boolean.toString(currentShowInvalid));
+ Utils.setDefaultValue(arguments, "show_invalid", Boolean.toString(savedShowInvalid));
}
public void onClick(Widget sender) {
diff --git a/frontend/client/src/autotest/tko/CompositeTestSet.java b/frontend/client/src/autotest/tko/CompositeTestSet.java
index 60abf65..4b80ecf 100644
--- a/frontend/client/src/autotest/tko/CompositeTestSet.java
+++ b/frontend/client/src/autotest/tko/CompositeTestSet.java
@@ -2,24 +2,35 @@
import autotest.common.Utils;
+import com.google.gwt.json.client.JSONObject;
+
import java.util.ArrayList;
import java.util.List;
-class CompositeTestSet implements TestSet {
+class CompositeTestSet extends TestSet {
private List<TestSet> testSets = new ArrayList<TestSet>();
public void add(TestSet tests) {
testSets.add(tests);
}
+
+ @Override
+ public JSONObject getInitialCondition() {
+ // we assume the initial condition is the same for all tests
+ assert !testSets.isEmpty();
+ return testSets.get(0).getInitialCondition();
+ }
- public String getCondition() {
+ @Override
+ public String getPartialSqlCondition() {
List<String> conditionParts = new ArrayList<String>();
for(TestSet testSet : testSets) {
- conditionParts.add("(" + testSet.getCondition() + ")");
+ conditionParts.add("(" + testSet.getPartialSqlCondition() + ")");
}
return Utils.joinStrings(" OR ", conditionParts);
}
+ @Override
public boolean isSingleTest() {
return testSets.size() == 1 && testSets.get(0).isSingleTest();
}
diff --git a/frontend/client/src/autotest/tko/ConditionTestSet.java b/frontend/client/src/autotest/tko/ConditionTestSet.java
index 4176d67..74df7a7 100644
--- a/frontend/client/src/autotest/tko/ConditionTestSet.java
+++ b/frontend/client/src/autotest/tko/ConditionTestSet.java
@@ -9,7 +9,7 @@
import java.util.List;
import java.util.Map;
-class ConditionTestSet implements TestSet {
+class ConditionTestSet extends TestSet {
private Map<String,String> fields = new HashMap<String,String>();
private boolean isSingleTest;
private JSONObject initialCondition = new JSONObject();
@@ -34,13 +34,14 @@
}
}
- public String getCondition() {
+ @Override
+ public JSONObject getInitialCondition() {
+ return Utils.copyJSONObject(initialCondition);
+ }
+
+ @Override
+ public String getPartialSqlCondition() {
ArrayList<String> parts = new ArrayList<String>();
- String sqlCondition = TkoUtils.getSqlCondition(initialCondition);
- if (!sqlCondition.trim().equals("")) {
- parts.add(sqlCondition);
- }
-
for (Map.Entry<String, String> entry : fields.entrySet()) {
String query = entry.getKey();
String value = entry.getValue();
@@ -60,6 +61,7 @@
return value.replace("'", "\\'");
}
+ @Override
public boolean isSingleTest() {
return isSingleTest;
}
diff --git a/frontend/client/src/autotest/tko/MachineQualHistogramFrontend.java b/frontend/client/src/autotest/tko/MachineQualHistogramFrontend.java
index bf74a09..509bd40 100644
--- a/frontend/client/src/autotest/tko/MachineQualHistogramFrontend.java
+++ b/frontend/client/src/autotest/tko/MachineQualHistogramFrontend.java
@@ -119,15 +119,7 @@
@SuppressWarnings("unused")
private void showDrilldown(final String filterString) {
- CommonPanel.getPanel().setCondition(new TestSet() {
- public String getCondition() {
- return filterString;
- }
-
- public boolean isSingleTest() {
- return false;
- }
- });
+ CommonPanel.getPanel().setSqlCondition(filterString);
listener.onSwitchToTable(TableViewConfig.PASS_RATE);
}
diff --git a/frontend/client/src/autotest/tko/SpreadsheetView.java b/frontend/client/src/autotest/tko/SpreadsheetView.java
index 1232892..a65b148 100644
--- a/frontend/client/src/autotest/tko/SpreadsheetView.java
+++ b/frontend/client/src/autotest/tko/SpreadsheetView.java
@@ -338,7 +338,7 @@
}
private void doDrilldown(TestSet tests, String newRowField, String newColumnField) {
- commonPanel.setCondition(tests);
+ commonPanel.refineCondition(tests);
currentRowFields = HeaderImpl.fromBaseType(Utils.wrapObjectWithList(newRowField));
currentColumnFields = HeaderImpl.fromBaseType(Utils.wrapObjectWithList(newColumnField));
updateWidgets();
@@ -453,7 +453,7 @@
}
private void switchToTable(final TestSet tests, boolean isTriageView) {
- commonPanel.setCondition(tests);
+ commonPanel.refineCondition(tests);
TableViewConfig config;
if (isTriageView) {
config = TableViewConfig.TRIAGE;
diff --git a/frontend/client/src/autotest/tko/TableView.java b/frontend/client/src/autotest/tko/TableView.java
index e5d084a..7c2a84b 100644
--- a/frontend/client/src/autotest/tko/TableView.java
+++ b/frontend/client/src/autotest/tko/TableView.java
@@ -318,7 +318,7 @@
}
private void doDrilldown(TestSet testSet) {
- commonPanel.setCondition(testSet);
+ commonPanel.refineCondition(testSet);
uncheckBothCheckboxes();
updateCheckboxes();
selectColumns(DEFAULT_COLUMNS);
diff --git a/frontend/client/src/autotest/tko/TestContextMenu.java b/frontend/client/src/autotest/tko/TestContextMenu.java
index 43d0632..6d107e1 100644
--- a/frontend/client/src/autotest/tko/TestContextMenu.java
+++ b/frontend/client/src/autotest/tko/TestContextMenu.java
@@ -2,6 +2,7 @@
import autotest.common.ui.ContextMenu;
+import com.google.gwt.json.client.JSONObject;
import com.google.gwt.user.client.Command;
public class TestContextMenu extends ContextMenu {
@@ -28,7 +29,7 @@
}
public void addLabelItems() {
- final String condition = tests.getCondition();
+ final JSONObject condition = tests.getCondition();
addItem("Invalidate tests", new Command() {
public void execute() {
labelManager.handleInvalidate(condition);
diff --git a/frontend/client/src/autotest/tko/TestLabelManager.java b/frontend/client/src/autotest/tko/TestLabelManager.java
index 48e1418..69e35fa 100644
--- a/frontend/client/src/autotest/tko/TestLabelManager.java
+++ b/frontend/client/src/autotest/tko/TestLabelManager.java
@@ -24,6 +24,7 @@
import com.google.gwt.user.client.ui.Widget;
public class TestLabelManager implements ClickListener {
+ public static final String INVALIDATED_LABEL = "invalidated";
private static final String ADD_TEXT = "Add label";
private static final String REMOVE_TEXT = "Remove label";
private static final int STACK_SELECT = 0, STACK_CREATE = 1;
@@ -41,7 +42,7 @@
private StackPanel stack = new StackPanel();
private Button submitButton = new Button(), cancelButton = new Button("Cancel");
- private String currentTestCondition;
+ private JSONObject currentTestCondition;
private TestLabelManager() {
@@ -93,7 +94,7 @@
cancelCreateLink.setVisible(visible);
}
- public void handleAddLabels(String testCondition) {
+ public void handleAddLabels(JSONObject testCondition) {
currentTestCondition = testCondition;
newLabelName.setText("");
@@ -110,12 +111,10 @@
showDialog(ADD_TEXT);
}
- public void handleRemoveLabels(String testCondition) {
+ public void handleRemoveLabels(JSONObject testCondition) {
currentTestCondition = testCondition;
- JSONObject args = new JSONObject();
- args.put("extra_where", new JSONString(currentTestCondition));
- rpcProxy.rpcCall("get_test_labels_for_tests", args, new JsonRpcCallback() {
+ rpcProxy.rpcCall("get_test_labels_for_tests", currentTestCondition, new JsonRpcCallback() {
@Override
public void onSuccess(JSONValue result) {
String[] labels = Utils.JSONObjectsToStrings(result.isArray(), "name");
@@ -193,9 +192,8 @@
rpcMethod = "test_label_remove_tests";
}
- JSONObject args = new JSONObject();
+ JSONObject args = Utils.copyJSONObject(currentTestCondition);
args.put("label_id", new JSONString(label));
- args.put("extra_where", new JSONString(currentTestCondition));
rpcProxy.rpcCall(rpcMethod, args, new JsonRpcCallback() {
@Override
public void onSuccess(JSONValue result) {
@@ -213,8 +211,8 @@
});
}
- public void handleInvalidate(String condition) {
+ public void handleInvalidate(JSONObject condition) {
currentTestCondition = condition;
- addOrRemoveLabel("invalidated", true);
+ addOrRemoveLabel(INVALIDATED_LABEL, true);
}
}
diff --git a/frontend/client/src/autotest/tko/TestSet.java b/frontend/client/src/autotest/tko/TestSet.java
index 3e450f0..71436c5 100644
--- a/frontend/client/src/autotest/tko/TestSet.java
+++ b/frontend/client/src/autotest/tko/TestSet.java
@@ -1,6 +1,24 @@
package autotest.tko;
-interface TestSet {
- public String getCondition();
- public boolean isSingleTest();
+import com.google.gwt.json.client.JSONObject;
+import com.google.gwt.json.client.JSONString;
+
+abstract class TestSet {
+ /**
+ * Get the full condition args for this test set.
+ */
+ public abstract JSONObject getInitialCondition();
+ /**
+ * Get the SQL condition for this test set within the global set.
+ */
+ public abstract String getPartialSqlCondition();
+ public abstract boolean isSingleTest();
+
+ public JSONObject getCondition() {
+ JSONObject condition = getInitialCondition();
+ String sqlCondition = TkoUtils.getSqlCondition(condition);
+ sqlCondition = TkoUtils.joinWithParens(" AND ", sqlCondition, getPartialSqlCondition());
+ condition.put("extra_where", new JSONString(sqlCondition));
+ return condition;
+ }
}
diff --git a/frontend/client/src/autotest/tko/TkoClient.java b/frontend/client/src/autotest/tko/TkoClient.java
index c3a44dc..b6545a8 100644
--- a/frontend/client/src/autotest/tko/TkoClient.java
+++ b/frontend/client/src/autotest/tko/TkoClient.java
@@ -52,9 +52,9 @@
final RootPanel tabsRoot = RootPanel.get("tabs");
tabsRoot.add(mainTabPanel);
+ commonPanel.initialize();
CustomHistory.processInitialToken();
mainTabPanel.initialize();
- commonPanel.initialize();
tabsRoot.removeStyleName("hidden");
}
diff --git a/frontend/client/src/autotest/tko/TkoUtils.java b/frontend/client/src/autotest/tko/TkoUtils.java
index 92651de..05142a7 100644
--- a/frontend/client/src/autotest/tko/TkoUtils.java
+++ b/frontend/client/src/autotest/tko/TkoUtils.java
@@ -4,6 +4,7 @@
import autotest.common.JsonRpcCallback;
import autotest.common.JsonRpcProxy;
import autotest.common.StaticDataRepository;
+import autotest.common.Utils;
import com.google.gwt.dom.client.Element;
import com.google.gwt.json.client.JSONArray;
@@ -13,6 +14,7 @@
import com.google.gwt.user.client.DOM;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
public class TkoUtils {
@@ -47,8 +49,7 @@
}
protected static void getTestId(TestSet test, final TestSelectionListener listener) {
- rpcProxy.rpcCall("get_test_views", getConditionParams(test.getCondition()),
- new JsonRpcCallback() {
+ rpcProxy.rpcCall("get_test_views", test.getCondition(), new JsonRpcCallback() {
@Override
public void onSuccess(JSONValue result) {
// just take the first result (there could be more than one due to
@@ -80,4 +81,11 @@
}
return condition.isString().stringValue();
}
+
+ static String joinWithParens(String joiner, String first, String second) {
+ if (!first.equals("")) {
+ first = "(" + first + ")";
+ }
+ return Utils.joinStrings(" AND ", Arrays.asList(new String[] {first, second}));
+ }
}
diff --git a/new_tko/tko/models.py b/new_tko/tko/models.py
index b25a24e..70802d3 100644
--- a/new_tko/tko/models.py
+++ b/new_tko/tko/models.py
@@ -247,39 +247,62 @@
return query.extra(select=extra_select)
- def _add_label_joins(self, query_set, suffix = '', join_condition='',
- exclude=False):
+ def _add_join(self, query_set, join_table, join_condition='',
+ join_key='test_idx', suffix='', exclude=False,
+ force_left_join=False):
table_name = self.model._meta.db_table
- first_join_alias = 'test_labels_tests' + suffix
- first_join_condition = '%s.test_id = %s.test_idx' % (first_join_alias,
- table_name)
+ join_alias = join_table + suffix
+ full_join_key = join_alias + '.' + join_key
+ full_join_condition = '%s = %s.test_idx' % (full_join_key, table_name)
if join_condition:
- first_join_condition += ' AND ' + join_condition
+ full_join_condition += ' AND (' + join_condition + ')'
+ if exclude or force_left_join:
+ join_type = 'LEFT JOIN'
+ else:
+ join_type = 'INNER JOIN'
+
filter_object = self._CustomSqlQ()
- filter_object.add_join('test_labels_tests',
- first_join_condition,
- 'LEFT JOIN',
- alias=first_join_alias)
+ filter_object.add_join(join_table,
+ full_join_condition,
+ join_type,
+ alias=join_alias)
+ if exclude:
+ filter_object.add_where(full_join_key + ' IS NULL')
+ return query_set.filter(filter_object).distinct()
+
+
+ def _add_label_joins(self, query_set, suffix=''):
+ query_set = self._add_join(query_set, 'test_labels_tests',
+ join_key='test_id', suffix=suffix,
+ force_left_join=True)
second_join_alias = 'test_labels' + suffix
second_join_condition = ('%s.id = %s.testlabel_id' %
- (second_join_alias, first_join_alias))
+ (second_join_alias,
+ 'test_labels_tests' + suffix))
+ filter_object = self._CustomSqlQ()
filter_object.add_join('test_labels',
second_join_condition,
'LEFT JOIN',
alias=second_join_alias)
+ return query_set.filter(filter_object)
- if exclude:
- filter_object.add_where(first_join_alias + '.testlabel_id IS NULL')
- return query_set.filter(filter_object).distinct()
+
+ def _add_attribute_join(self, query_set, suffix='', join_condition='',
+ exclude=False):
+ return self._add_join(query_set, 'test_attributes',
+ join_condition=join_condition,
+ suffix=suffix, exclude=exclude)
def _get_label_ids_from_names(self, label_names):
+ if not label_names:
+ return []
query = TestLabel.objects.filter(name__in=label_names).values('id')
return [label['id'] for label in query]
- def get_query_set_with_labels(self, filter_data):
+ def get_query_set_with_joins(self, filter_data):
exclude_labels = filter_data.pop('exclude_labels', [])
query_set = self.get_query_set()
joined = False
@@ -288,15 +311,33 @@
query_set = self._add_label_joins(query_set)
joined = True
- if exclude_labels:
- label_ids = self._get_label_ids_from_names(exclude_labels)
- if label_ids:
- condition = ('test_labels_tests_exclude.testlabel_id IN (%s)' %
- ','.join(str(label_id) for label_id in label_ids))
- query_set = self._add_label_joins(query_set, suffix='_exclude',
- join_condition=condition,
- exclude=True)
- joined = True
+ exclude_label_ids = self._get_label_ids_from_names(exclude_labels)
+ if exclude_label_ids:
+ condition = ('test_labels_tests_exclude.testlabel_id IN (%s)' %
+ ','.join(str(label_id)
+ for label_id in exclude_label_ids))
+ query_set = self._add_join(query_set, 'test_labels_tests',
+ join_key='test_id',
+ suffix='_exclude',
+ join_condition=condition,
+ exclude=True)
+ joined = True
+
+ include_attributes_where = filter_data.pop('include_attributes_where',
+ '')
+ exclude_attributes_where = filter_data.pop('exclude_attributes_where',
+ '')
+ if include_attributes_where:
+ query_set = self._add_attribute_join(
+ query_set, suffix='_include',
+ join_condition=include_attributes_where)
+ joined = True
+ if exclude_attributes_where:
+ query_set = self._add_attribute_join(
+ query_set, suffix='_exclude',
+ join_condition=exclude_attributes_where,
+ exclude=True)
+ joined = True
if not joined:
filter_data['no_distinct'] = True
@@ -384,7 +425,7 @@
@classmethod
def query_objects(cls, filter_data, initial_query=None):
if initial_query is None:
- initial_query = cls.objects.get_query_set_with_labels(filter_data)
+ initial_query = cls.objects.get_query_set_with_joins(filter_data)
return super(TestView, cls).query_objects(filter_data,
initial_query=initial_query)