Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15353742
D12455.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
14 KB
Referenced Files
None
Subscribers
None
D12455.diff
View Options
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
@@ -2324,6 +2324,7 @@
'PhabricatorProjectsPolicyRule' => 'applications/policy/rule/PhabricatorProjectsPolicyRule.php',
'PhabricatorPygmentSetupCheck' => 'applications/config/check/PhabricatorPygmentSetupCheck.php',
'PhabricatorQuery' => 'infrastructure/query/PhabricatorQuery.php',
+ 'PhabricatorQueryConstraint' => 'infrastructure/query/constraint/PhabricatorQueryConstraint.php',
'PhabricatorQueryOrderItem' => 'infrastructure/query/order/PhabricatorQueryOrderItem.php',
'PhabricatorQueryOrderTestCase' => 'infrastructure/query/order/__tests__/PhabricatorQueryOrderTestCase.php',
'PhabricatorQueryOrderVector' => 'infrastructure/query/order/PhabricatorQueryOrderVector.php',
@@ -5702,6 +5703,7 @@
'PhabricatorProjectWatchController' => 'PhabricatorProjectController',
'PhabricatorProjectsPolicyRule' => 'PhabricatorPolicyRule',
'PhabricatorPygmentSetupCheck' => 'PhabricatorSetupCheck',
+ 'PhabricatorQueryConstraint' => 'Phobject',
'PhabricatorQueryOrderItem' => 'Phobject',
'PhabricatorQueryOrderTestCase' => 'PhabricatorTestCase',
'PhabricatorQueryOrderVector' => array(
diff --git a/src/applications/conpherence/query/ConpherenceThreadQuery.php b/src/applications/conpherence/query/ConpherenceThreadQuery.php
--- a/src/applications/conpherence/query/ConpherenceThreadQuery.php
+++ b/src/applications/conpherence/query/ConpherenceThreadQuery.php
@@ -121,7 +121,7 @@
return $conpherences;
}
- private function buildGroupClause($conn_r) {
+ protected function buildGroupClause(AphrontDatabaseConnection $conn_r) {
if ($this->participantPHIDs !== null) {
return 'GROUP BY conpherence_thread.id';
} else {
diff --git a/src/applications/diffusion/query/DiffusionCommitQuery.php b/src/applications/diffusion/query/DiffusionCommitQuery.php
--- a/src/applications/diffusion/query/DiffusionCommitQuery.php
+++ b/src/applications/diffusion/query/DiffusionCommitQuery.php
@@ -542,7 +542,7 @@
}
}
- private function buildGroupClause(AphrontDatabaseConnection $conn_r) {
+ protected function buildGroupClause(AphrontDatabaseConnection $conn_r) {
$should_group = $this->shouldJoinAudits();
// TODO: Currently, the audit table is missing a unique key, so we may
diff --git a/src/applications/feed/query/PhabricatorFeedQuery.php b/src/applications/feed/query/PhabricatorFeedQuery.php
--- a/src/applications/feed/query/PhabricatorFeedQuery.php
+++ b/src/applications/feed/query/PhabricatorFeedQuery.php
@@ -82,7 +82,7 @@
return $this->formatWhereClause($where);
}
- private function buildGroupClause(AphrontDatabaseConnection $conn_r) {
+ protected function buildGroupClause(AphrontDatabaseConnection $conn_r) {
if ($this->filterPHIDs) {
return qsprintf($conn_r, 'GROUP BY ref.chronologicalKey');
} else {
diff --git a/src/applications/legalpad/query/LegalpadDocumentQuery.php b/src/applications/legalpad/query/LegalpadDocumentQuery.php
--- a/src/applications/legalpad/query/LegalpadDocumentQuery.php
+++ b/src/applications/legalpad/query/LegalpadDocumentQuery.php
@@ -157,7 +157,7 @@
return implode(' ', $joins);
}
- private function buildGroupClause(AphrontDatabaseConnection $conn_r) {
+ protected function buildGroupClause(AphrontDatabaseConnection $conn_r) {
if ($this->contributorPHIDs || $this->signerPHIDs) {
return 'GROUP BY d.id';
} else {
diff --git a/src/applications/maniphest/query/ManiphestTaskQuery.php b/src/applications/maniphest/query/ManiphestTaskQuery.php
--- a/src/applications/maniphest/query/ManiphestTaskQuery.php
+++ b/src/applications/maniphest/query/ManiphestTaskQuery.php
@@ -837,7 +837,7 @@
return implode(' ', $joins);
}
- private function buildGroupClause(AphrontDatabaseConnection $conn_r) {
+ protected function buildGroupClause(AphrontDatabaseConnection $conn_r) {
$joined_multiple_rows = (count($this->projectPHIDs) > 1) ||
(count($this->anyProjectPHIDs) > 1) ||
$this->shouldJoinBlockingTasks() ||
diff --git a/src/applications/people/query/PhabricatorPeopleQuery.php b/src/applications/people/query/PhabricatorPeopleQuery.php
--- a/src/applications/people/query/PhabricatorPeopleQuery.php
+++ b/src/applications/people/query/PhabricatorPeopleQuery.php
@@ -186,7 +186,7 @@
return $users;
}
- private function buildGroupClause(AphrontDatabaseConnection $conn) {
+ protected function buildGroupClause(AphrontDatabaseConnection $conn) {
if ($this->nameTokens) {
return qsprintf(
$conn,
diff --git a/src/applications/project/query/PhabricatorProjectQuery.php b/src/applications/project/query/PhabricatorProjectQuery.php
--- a/src/applications/project/query/PhabricatorProjectQuery.php
+++ b/src/applications/project/query/PhabricatorProjectQuery.php
@@ -328,7 +328,7 @@
return $this->formatWhereClause($where);
}
- private function buildGroupClause($conn_r) {
+ protected function buildGroupClause(AphrontDatabaseConnection $conn_r) {
if ($this->memberPHIDs || $this->nameTokens) {
return 'GROUP BY p.id';
} else {
diff --git a/src/infrastructure/query/constraint/PhabricatorQueryConstraint.php b/src/infrastructure/query/constraint/PhabricatorQueryConstraint.php
new file mode 100644
--- /dev/null
+++ b/src/infrastructure/query/constraint/PhabricatorQueryConstraint.php
@@ -0,0 +1,36 @@
+<?php
+
+final class PhabricatorQueryConstraint extends Phobject {
+
+ const OPERATOR_AND = 'and';
+ const OPERATOR_OR = 'or';
+ const OPERATOR_NOT = 'not';
+ const OPERATOR_NULL = 'null';
+
+ private $operator;
+ private $value;
+
+ public function __construct($operator, $value) {
+ $this->operator = $operator;
+ $this->value = $value;
+ }
+
+ public function setOperator($operator) {
+ $this->operator = $operator;
+ return $this;
+ }
+
+ public function getOperator() {
+ return $this->operator;
+ }
+
+ public function setValue($value) {
+ $this->value = $value;
+ return $this;
+ }
+
+ public function getValue() {
+ return $this->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
@@ -9,6 +9,7 @@
* @task customfield Integration with CustomField
* @task paging Paging
* @task order Result Ordering
+ * @task edgelogic Working with Edge Logic
*/
abstract class PhabricatorCursorPagedPolicyAwareQuery
extends PhabricatorPolicyAwareQuery {
@@ -202,6 +203,8 @@
$select[] = '*';
}
+ $select[] = $this->buildEdgeLogicSelectClause($conn);
+
return $select;
}
@@ -220,6 +223,7 @@
*/
protected function buildJoinClauseParts(AphrontDatabaseConnection $conn) {
$joins = array();
+ $joins[] = $this->buildEdgeLogicJoinClause($conn);
return $joins;
}
@@ -239,6 +243,7 @@
protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
$where = array();
$where[] = $this->buildPagingClause($conn);
+ $where[] = $this->buildEdgeLogicWhereClause($conn);
return $where;
}
@@ -257,10 +262,43 @@
*/
protected function buildHavingClauseParts(AphrontDatabaseConnection $conn) {
$having = array();
+ $having[] = $this->buildEdgeLogicHavingClause($conn);
return $having;
}
+ /**
+ * @task clauses
+ */
+ protected function buildGroupClause(AphrontDatabaseConnection $conn) {
+ if (!$this->shouldGroupQueryResultRows()) {
+ return '';
+ }
+
+ return qsprintf(
+ $conn,
+ 'GROUP BY %Q',
+ $this->getApplicationSearchObjectPHIDColumn());
+ }
+
+
+ /**
+ * @task clauses
+ */
+ protected function shouldGroupQueryResultRows() {
+ if ($this->shouldGroupEdgeLogicResultRows()) {
+ return true;
+ }
+
+ if ($this->getApplicationSearchMayJoinMultipleRows()) {
+ return true;
+ }
+
+ return false;
+ }
+
+
+
/* -( Paging )------------------------------------------------------------- */
@@ -1218,4 +1256,232 @@
}
+/* -( Edge Logic )--------------------------------------------------------- */
+
+
+ /**
+ * @task edgelogic
+ */
+ public function withEdgeLogicConstraints($edge_type, array $constraints) {
+ assert_instances_of($constraints, 'PhabricatorQueryConstraint');
+
+ $constraints = mgroup($constraints, 'getOperator');
+ foreach ($constraints as $operator => $list) {
+ foreach ($list as $item) {
+ $value = $item->getValue();
+ $this->edgeLogicConstraints[$edge_type][$operator][$value] = $item;
+ }
+ }
+
+ return $this;
+ }
+
+
+ /**
+ * @task edgelogic
+ */
+ public function buildEdgeLogicSelectClause(AphrontDatabaseConnection $conn) {
+ $select = array();
+
+ foreach ($this->edgeLogicConstraints as $type => $constraints) {
+ foreach ($constraints as $operator => $list) {
+ $alias = $this->getEdgeLogicTableAlias($operator, $type);
+ switch ($operator) {
+ case PhabricatorQueryConstraint::OPERATOR_AND:
+ if (count($list) > 1) {
+ $select[] = qsprintf(
+ $conn,
+ 'COUNT(DISTINCT(%T.dst)) %T',
+ $alias,
+ $this->buildEdgeLogicTableAliasCount($alias));
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ return $select;
+ }
+
+
+ /**
+ * @task edgelogic
+ */
+ public function buildEdgeLogicJoinClause(AphrontDatabaseConnection $conn) {
+ $edge_table = PhabricatorEdgeConfig::TABLE_NAME_EDGE;
+ $phid_column = $this->getApplicationSearchObjectPHIDColumn();
+
+ $joins = array();
+ foreach ($this->edgeLogicConstraints as $type => $constraints) {
+ foreach ($constraints as $operator => $list) {
+ $alias = $this->getEdgeLogicTableAlias($operator, $type);
+ switch ($operator) {
+ case PhabricatorQueryConstraint::OPERATOR_NOT:
+ $joins[] = qsprintf(
+ $conn,
+ 'LEFT JOIN %T %T ON %Q = %T.src AND %T.type = %d
+ AND %T.dst IN (%Ls)',
+ $edge_table,
+ $alias,
+ $phid_column,
+ $alias,
+ $alias,
+ $type,
+ $alias,
+ mpull($list, 'getValue'));
+ break;
+ case PhabricatorQueryConstraint::OPERATOR_AND:
+ case PhabricatorQueryConstraint::OPERATOR_OR:
+ $joins[] = qsprintf(
+ $conn,
+ 'JOIN %T %T ON %Q = %T.src AND %T.type = %d
+ AND %T.dst IN (%Ls)',
+ $edge_table,
+ $alias,
+ $phid_column,
+ $alias,
+ $alias,
+ $type,
+ $alias,
+ mpull($list, 'getValue'));
+ break;
+ case PhabricatorQueryConstraint::OPERATOR_NULL:
+ $joins[] = qsprintf(
+ $conn,
+ 'LEFT JOIN %T %T ON %Q = %T.src AND %T.type = %d',
+ $edge_table,
+ $alias,
+ $phid_column,
+ $alias,
+ $alias,
+ $type);
+ break;
+ }
+ }
+ }
+
+ return $joins;
+ }
+
+
+ /**
+ * @task edgelogic
+ */
+ public function buildEdgeLogicWhereClause(AphrontDatabaseConnection $conn) {
+ $where = array();
+
+ foreach ($this->edgeLogicConstraints as $type => $constraints) {
+
+ $full = array();
+ $null = array();
+
+ foreach ($constraints as $operator => $list) {
+ $alias = $this->getEdgeLogicTableAlias($operator, $type);
+ switch ($operator) {
+ case PhabricatorQueryConstraint::OPERATOR_NOT:
+ $full[] = qsprintf(
+ $conn,
+ '%T.dst IS NULL',
+ $alias);
+ break;
+ case PhabricatorQueryConstraint::OPERATOR_AND:
+ case PhabricatorQueryConstraint::OPERATOR_OR:
+ break;
+ case PhabricatorQueryConstraint::OPERATOR_NULL:
+ $null[] = qsprintf(
+ $conn,
+ '%T.dst IS NULL',
+ $alias);
+ break;
+ }
+ }
+
+ if ($full && $null) {
+ $full = $this->formatWhereSubclause($full);
+ $null = $this->formatWhereSubclause($null);
+ $where[] = qsprintf($conn, '(%Q OR %Q)', $full, $null);
+ } else if ($full) {
+ foreach ($full as $condition) {
+ $where[] = $condition;
+ }
+ } else if ($null) {
+ foreach ($null as $condition) {
+ $where[] = $condition;
+ }
+ }
+ }
+
+ return $where;
+ }
+
+
+ /**
+ * @task edgelogic
+ */
+ public function buildEdgeLogicHavingClause(AphrontDatabaseConnection $conn) {
+ $having = array();
+
+ foreach ($this->edgeLogicConstraints as $type => $constraints) {
+ foreach ($constraints as $operator => $list) {
+ $alias = $this->getEdgeLogicTableAlias($operator, $type);
+ switch ($operator) {
+ case PhabricatorQueryConstraint::OPERATOR_AND:
+ if (count($list) > 1) {
+ $having[] = qsprintf(
+ $conn,
+ '%T = %d',
+ $this->buildEdgeLogicTableAliasCount($alias),
+ count($list));
+ }
+ break;
+ }
+ }
+ }
+
+ return $having;
+ }
+
+
+ /**
+ * @task edgelogic
+ */
+ public function shouldGroupEdgeLogicResultRows() {
+ foreach ($this->edgeLogicConstraints as $type => $constraints) {
+ foreach ($constraints as $operator => $list) {
+ switch ($operator) {
+ case PhabricatorQueryConstraint::OPERATOR_NOT:
+ case PhabricatorQueryConstraint::OPERATOR_AND:
+ case PhabricatorQueryConstraint::OPERATOR_OR:
+ if (count($list) > 1) {
+ return true;
+ }
+ break;
+ case PhabricatorQueryConstraint::OPERATOR_NULL:
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+
+ /**
+ * @task edgelogic
+ */
+ private function getEdgeLogicTableAlias($operator, $type) {
+ return 'edgelogic_'.$operator.'_'.$type;
+ }
+
+
+ /**
+ * @task edgelogic
+ */
+ private function buildEdgeLogicTableAliasCount($alias) {
+ return $alias.'_count';
+ }
+
+
}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Tue, Mar 11, 11:58 PM (4 h, 4 m ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7560582
Default Alt Text
D12455.diff (14 KB)
Attached To
Mode
D12455: Add "Edge Logic" support to PolicyAwareQuery
Attached
Detach File
Event Timeline
Log In to Comment