Page MenuHomePhabricator

D18543.diff
No OneTemporary

D18543.diff

diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -3686,6 +3686,7 @@
'PhabricatorProjectLockTransaction' => 'applications/project/xaction/PhabricatorProjectLockTransaction.php',
'PhabricatorProjectLogicalAncestorDatasource' => 'applications/project/typeahead/PhabricatorProjectLogicalAncestorDatasource.php',
'PhabricatorProjectLogicalDatasource' => 'applications/project/typeahead/PhabricatorProjectLogicalDatasource.php',
+ 'PhabricatorProjectLogicalOnlyDatasource' => 'applications/project/typeahead/PhabricatorProjectLogicalOnlyDatasource.php',
'PhabricatorProjectLogicalOrNotDatasource' => 'applications/project/typeahead/PhabricatorProjectLogicalOrNotDatasource.php',
'PhabricatorProjectLogicalUserDatasource' => 'applications/project/typeahead/PhabricatorProjectLogicalUserDatasource.php',
'PhabricatorProjectLogicalViewerDatasource' => 'applications/project/typeahead/PhabricatorProjectLogicalViewerDatasource.php',
@@ -9179,6 +9180,7 @@
'PhabricatorProjectLockTransaction' => 'PhabricatorProjectTransactionType',
'PhabricatorProjectLogicalAncestorDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
'PhabricatorProjectLogicalDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
+ 'PhabricatorProjectLogicalOnlyDatasource' => 'PhabricatorTypeaheadDatasource',
'PhabricatorProjectLogicalOrNotDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
'PhabricatorProjectLogicalUserDatasource' => 'PhabricatorTypeaheadCompositeDatasource',
'PhabricatorProjectLogicalViewerDatasource' => 'PhabricatorTypeaheadDatasource',
diff --git a/src/applications/project/typeahead/PhabricatorProjectLogicalDatasource.php b/src/applications/project/typeahead/PhabricatorProjectLogicalDatasource.php
--- a/src/applications/project/typeahead/PhabricatorProjectLogicalDatasource.php
+++ b/src/applications/project/typeahead/PhabricatorProjectLogicalDatasource.php
@@ -21,6 +21,7 @@
new PhabricatorProjectLogicalAncestorDatasource(),
new PhabricatorProjectLogicalOrNotDatasource(),
new PhabricatorProjectLogicalViewerDatasource(),
+ new PhabricatorProjectLogicalOnlyDatasource(),
new PhabricatorProjectLogicalUserDatasource(),
);
}
diff --git a/src/applications/project/typeahead/PhabricatorProjectLogicalOnlyDatasource.php b/src/applications/project/typeahead/PhabricatorProjectLogicalOnlyDatasource.php
new file mode 100644
--- /dev/null
+++ b/src/applications/project/typeahead/PhabricatorProjectLogicalOnlyDatasource.php
@@ -0,0 +1,76 @@
+<?php
+
+final class PhabricatorProjectLogicalOnlyDatasource
+ extends PhabricatorTypeaheadDatasource {
+
+ public function getBrowseTitle() {
+ return pht('Browse Only');
+ }
+
+ public function getPlaceholderText() {
+ return pht('Type only()...');
+ }
+
+ public function getDatasourceApplicationClass() {
+ return 'PhabricatorProjectApplication';
+ }
+
+ public function getDatasourceFunctions() {
+ return array(
+ 'only' => array(
+ 'name' => pht('Only Match Other Constraints'),
+ 'summary' => pht(
+ 'Find results with only the specified tags.'),
+ 'description' => pht(
+ "This function is used with other tags, and causes the query to ".
+ "match only results with exactly those tags. For example, to find ".
+ "tasks tagged only iOS:".
+ "\n\n".
+ "> ios, only()".
+ "\n\n".
+ "This will omit results with any other project tag."),
+ ),
+ );
+ }
+
+ public function loadResults() {
+ $results = array(
+ $this->renderOnlyFunctionToken(),
+ );
+ return $this->filterResultsAgainstTokens($results);
+ }
+
+ protected function evaluateFunction($function, array $argv_list) {
+ $results = array();
+
+ $results[] = new PhabricatorQueryConstraint(
+ PhabricatorQueryConstraint::OPERATOR_ONLY,
+ null);
+
+ return $results;
+ }
+
+ public function renderFunctionTokens(
+ $function,
+ array $argv_list) {
+
+ $tokens = array();
+ foreach ($argv_list as $argv) {
+ $tokens[] = PhabricatorTypeaheadTokenView::newFromTypeaheadResult(
+ $this->renderOnlyFunctionToken());
+ }
+
+ return $tokens;
+ }
+
+ private function renderOnlyFunctionToken() {
+ return $this->newFunctionResult()
+ ->setName(pht('Only'))
+ ->setPHID('only()')
+ ->setIcon('fa-asterisk')
+ ->setUnique(true)
+ ->addAttribute(
+ pht('Select only results with exactly the other specified tags.'));
+ }
+
+}
diff --git a/src/applications/project/typeahead/PhabricatorProjectLogicalViewerDatasource.php b/src/applications/project/typeahead/PhabricatorProjectLogicalViewerDatasource.php
--- a/src/applications/project/typeahead/PhabricatorProjectLogicalViewerDatasource.php
+++ b/src/applications/project/typeahead/PhabricatorProjectLogicalViewerDatasource.php
@@ -29,7 +29,7 @@
"\n\n".
"This normally means //your// projects, but if you save a query ".
"using this function and send it to someone else, it will mean ".
- "//their// projects when they run it (they become the currnet ".
+ "//their// projects when they run it (they become the current ".
"viewer). This can be useful for building dashboard panels."),
),
);
diff --git a/src/infrastructure/query/constraint/PhabricatorQueryConstraint.php b/src/infrastructure/query/constraint/PhabricatorQueryConstraint.php
--- a/src/infrastructure/query/constraint/PhabricatorQueryConstraint.php
+++ b/src/infrastructure/query/constraint/PhabricatorQueryConstraint.php
@@ -8,6 +8,7 @@
const OPERATOR_NULL = 'null';
const OPERATOR_ANCESTOR = 'ancestor';
const OPERATOR_EMPTY = 'empty';
+ const OPERATOR_ONLY = 'only';
private $operator;
private $value;
diff --git a/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php b/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php
--- a/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php
+++ b/src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php
@@ -2069,6 +2069,27 @@
$op_null = PhabricatorQueryConstraint::OPERATOR_NULL;
$has_null = isset($constraints[$op_null]);
+ // If we're going to process an only() operator, build a list of the
+ // acceptable set of PHIDs first. We'll only match results which have
+ // no edges to any other PHIDs.
+ $all_phids = array();
+ if (isset($constraints[PhabricatorQueryConstraint::OPERATOR_ONLY])) {
+ foreach ($constraints as $operator => $list) {
+ switch ($operator) {
+ case PhabricatorQueryConstraint::OPERATOR_ANCESTOR:
+ case PhabricatorQueryConstraint::OPERATOR_AND:
+ case PhabricatorQueryConstraint::OPERATOR_OR:
+ foreach ($list as $constraint) {
+ $value = (array)$constraint->getValue();
+ foreach ($value as $v) {
+ $all_phids[$v] = $v;
+ }
+ }
+ break;
+ }
+ }
+ }
+
foreach ($constraints as $operator => $list) {
$alias = $this->getEdgeLogicTableAlias($operator, $type);
@@ -2133,6 +2154,20 @@
$alias,
$type);
break;
+ case PhabricatorQueryConstraint::OPERATOR_ONLY:
+ $joins[] = qsprintf(
+ $conn,
+ 'LEFT JOIN %T %T ON %Q = %T.src AND %T.type = %d
+ AND %T.dst NOT IN (%Ls)',
+ $edge_table,
+ $alias,
+ $phid_column,
+ $alias,
+ $alias,
+ $type,
+ $alias,
+ $all_phids);
+ break;
}
}
}
@@ -2159,6 +2194,7 @@
$alias = $this->getEdgeLogicTableAlias($operator, $type);
switch ($operator) {
case PhabricatorQueryConstraint::OPERATOR_NOT:
+ case PhabricatorQueryConstraint::OPERATOR_ONLY:
$full[] = qsprintf(
$conn,
'%T.dst IS NULL',
@@ -2258,6 +2294,7 @@
// discussion, see T12753.
return true;
case PhabricatorQueryConstraint::OPERATOR_NULL:
+ case PhabricatorQueryConstraint::OPERATOR_ONLY:
return true;
}
}
@@ -2375,6 +2412,34 @@
}
}
+ $op_and = PhabricatorQueryConstraint::OPERATOR_AND;
+ $op_or = PhabricatorQueryConstraint::OPERATOR_OR;
+ $op_ancestor = PhabricatorQueryConstraint::OPERATOR_ANCESTOR;
+
+ foreach ($this->edgeLogicConstraints as $type => $constraints) {
+ foreach ($constraints as $operator => $list) {
+ switch ($operator) {
+ case PhabricatorQueryConstraint::OPERATOR_ONLY:
+ if (count($list) > 1) {
+ throw new PhabricatorEmptyQueryException(
+ pht(
+ 'This query specifies only() more than once.'));
+ }
+
+ $have_and = idx($constraints, $op_and);
+ $have_or = idx($constraints, $op_or);
+ $have_ancestor = idx($constraints, $op_ancestor);
+ if (!$have_and && !$have_or && !$have_ancestor) {
+ throw new PhabricatorEmptyQueryException(
+ pht(
+ 'This query specifies only(), but no other constraints '.
+ 'which it can apply to.'));
+ }
+ break;
+ }
+ }
+ }
+
$this->edgeLogicConstraintsAreValid = true;
return $this;

File Metadata

Mime Type
text/plain
Expires
Wed, May 22, 8:52 AM (3 w, 4 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6297007
Default Alt Text
D18543.diff (9 KB)

Event Timeline