Page MenuHomePhabricator

D12455.diff
No OneTemporary

D12455.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
@@ -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

Mime Type
text/plain
Expires
Thu, May 9, 8:49 PM (3 w, 6 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
6277228
Default Alt Text
D12455.diff (14 KB)

Event Timeline