@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Implement function-driven logical project queries in Differential

Summary:
Ref T4100. Ref T5595. This implements these fields in one mega-field:

- Projects
- Not in projects
- In any project
- Include results in no projects
- In users' projects

Hopefully, this is a step in the right direction.

Test Plan: {F375555}

Reviewers: btrahan

Reviewed By: btrahan

Subscribers: joshuaspence, chad, epriestley

Maniphest Tasks: T4100, T5595

Differential Revision: https://secure.phabricator.com/D12463

+95 -15
+15 -6
src/applications/differential/query/DifferentialRevisionQuery.php
··· 596 596 private function buildSelectStatement(AphrontDatabaseConnection $conn_r) { 597 597 $table = new DifferentialRevision(); 598 598 599 - $select = qsprintf( 599 + $select = $this->buildSelectClause($conn_r); 600 + 601 + $from = qsprintf( 600 602 $conn_r, 601 - 'SELECT r.* FROM %T r', 603 + 'FROM %T r', 602 604 $table->getTableName()); 603 605 604 606 $joins = $this->buildJoinsClause($conn_r); 605 607 $where = $this->buildWhereClause($conn_r); 606 608 $group_by = $this->buildGroupByClause($conn_r); 609 + $having = $this->buildHavingClause($conn_r); 607 610 608 611 $this->buildingGlobalOrder = false; 609 612 $order_by = $this->buildOrderClause($conn_r); ··· 612 615 613 616 return qsprintf( 614 617 $conn_r, 615 - '(%Q %Q %Q %Q %Q %Q)', 618 + '(%Q %Q %Q %Q %Q %Q %Q %Q)', 616 619 $select, 620 + $from, 617 621 $joins, 618 622 $where, 619 623 $group_by, 624 + $having, 620 625 $order_by, 621 626 $limit); 622 627 } ··· 684 689 DifferentialRevision::TABLE_COMMIT); 685 690 } 686 691 687 - $joins = implode(' ', $joins); 692 + $joins[] = $this->buildJoinClauseParts($conn_r); 688 693 689 - return $joins; 694 + return $this->formatJoinClause($joins); 690 695 } 691 696 692 697 ··· 839 844 "Unknown revision status filter constant '{$this->status}'!"); 840 845 } 841 846 842 - $where[] = $this->buildPagingClause($conn_r); 847 + $where[] = $this->buildWhereClauseParts($conn_r); 843 848 return $this->formatWhereClause($where); 844 849 } 845 850 ··· 1159 1164 1160 1165 public function getQueryApplicationClass() { 1161 1166 return 'PhabricatorDifferentialApplication'; 1167 + } 1168 + 1169 + protected function getPrimaryTableAlias() { 1170 + return 'r'; 1162 1171 } 1163 1172 1164 1173 }
+14
src/applications/differential/query/DifferentialRevisionSearchEngine.php
··· 46 46 'repositoryPHIDs', 47 47 $request->getArr('repositories')); 48 48 49 + // TODO: Implement "readProjectsFromRequest(...)" to improve this. 50 + $saved->setParameter( 51 + 'projects', 52 + $this->readListFromRequest($request, 'projects')); 53 + 49 54 $saved->setParameter( 50 55 'draft', 51 56 $request->getBool('draft')); ··· 75 80 if ($responsible_phids) { 76 81 $query->withResponsibleUsers($responsible_phids); 77 82 } 83 + 84 + $this->setQueryProjects($query, $saved); 78 85 79 86 $author_phids = $saved->getParameter('authorPHIDs', array()); 80 87 if ($author_phids) { ··· 127 134 $subscriber_phids = $saved->getParameter('subscriberPHIDs', array()); 128 135 $repository_phids = $saved->getParameter('repositoryPHIDs', array()); 129 136 $only_draft = $saved->getParameter('draft', false); 137 + $projects = $saved->getParameter('projects', array()); 130 138 131 139 $form 132 140 ->appendControl( ··· 159 167 ->setName('repositories') 160 168 ->setDatasource(new DiffusionRepositoryDatasource()) 161 169 ->setValue($repository_phids)) 170 + ->appendControl( 171 + id(new AphrontFormTokenizerControl()) 172 + ->setLabel(pht('Projects')) 173 + ->setName('projects') 174 + ->setDatasource(new PhabricatorProjectLogicalDatasource()) 175 + ->setValue($projects)) 162 176 ->appendChild( 163 177 id(new AphrontFormSelectControl()) 164 178 ->setLabel(pht('Status'))
+6 -6
src/applications/project/typeahead/PhabricatorProjectLogicalAndDatasource.php
··· 17 17 ); 18 18 } 19 19 20 - public function evaluateTokens(array $tokens) { 21 - $results = parent::evaluateTokens($tokens); 22 - 20 + protected function didEvaluateTokens(array $results) { 23 21 foreach ($results as $key => $result) { 24 - $results[$key] = new PhabricatorQueryConstraint( 25 - PhabricatorQueryConstraint::OPERATOR_AND, 26 - $result); 22 + if (is_string($result)) { 23 + $results[$key] = new PhabricatorQueryConstraint( 24 + PhabricatorQueryConstraint::OPERATOR_AND, 25 + $result); 26 + } 27 27 } 28 28 29 29 return $results;
+1 -1
src/applications/project/typeahead/PhabricatorProjectLogicalOrNotDatasource.php
··· 75 75 $phid); 76 76 } 77 77 78 - return $phids; 78 + return $results; 79 79 } 80 80 81 81 public function renderFunctionTokens($function, array $argv_list) {
+1 -1
src/applications/project/typeahead/PhabricatorProjectLogicalViewerDatasource.php
··· 56 56 return $results; 57 57 } 58 58 59 - public function renderViewerProjectsFunctionTokens( 59 + public function renderFunctionTokens( 60 60 $function, 61 61 array $argv_list) { 62 62
+17
src/applications/search/engine/PhabricatorApplicationSearchEngine.php
··· 219 219 return $named_queries; 220 220 } 221 221 222 + protected function setQueryProjects( 223 + PhabricatorCursorPagedPolicyAwareQuery $query, 224 + PhabricatorSavedQuery $saved) { 225 + 226 + $datasource = id(new PhabricatorProjectLogicalDatasource()) 227 + ->setViewer($this->requireViewer()); 228 + 229 + $projects = $saved->getParameter('projects', array()); 230 + $constraints = $datasource->evaluateTokens($projects); 231 + 232 + if ($constraints) { 233 + $query->withEdgeLogicConstraints( 234 + PhabricatorProjectObjectHasProjectEdgeType::EDGECONST, 235 + $constraints); 236 + } 237 + } 238 + 222 239 223 240 /* -( Applications )------------------------------------------------------- */ 224 241
+6
src/applications/typeahead/datasource/PhabricatorTypeaheadCompositeDatasource.php
··· 117 117 return $this->usable; 118 118 } 119 119 120 + protected function didEvaluateTokens(array $results) { 121 + foreach ($this->getUsableDatasources() as $source) { 122 + $results = $source->didEvaluateTokens($results); 123 + } 124 + return $results; 125 + } 120 126 121 127 protected function canEvaluateFunction($function) { 122 128 foreach ($this->getUsableDatasources() as $source) {
+10
src/applications/typeahead/datasource/PhabricatorTypeaheadDatasource.php
··· 324 324 } 325 325 } 326 326 327 + $results = $this->didEvaluateTokens($results); 328 + 329 + return $results; 330 + } 331 + 332 + 333 + /** 334 + * @task functions 335 + */ 336 + protected function didEvaluateTokens(array $results) { 327 337 return $results; 328 338 } 329 339
+25 -1
src/infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php
··· 21 21 private $internalPaging; 22 22 private $orderVector; 23 23 private $builtinOrder; 24 + private $edgeLogicConstraints = array(); 24 25 25 26 protected function getPageCursors(array $page) { 26 27 return array( ··· 1315 1316 1316 1317 $joins = array(); 1317 1318 foreach ($this->edgeLogicConstraints as $type => $constraints) { 1319 + 1320 + $op_null = PhabricatorQueryConstraint::OPERATOR_NULL; 1321 + $has_null = isset($constraints[$op_null]); 1322 + 1318 1323 foreach ($constraints as $operator => $list) { 1319 1324 $alias = $this->getEdgeLogicTableAlias($operator, $type); 1320 1325 switch ($operator) { ··· 1334 1339 break; 1335 1340 case PhabricatorQueryConstraint::OPERATOR_AND: 1336 1341 case PhabricatorQueryConstraint::OPERATOR_OR: 1342 + // If we're including results with no matches, we have to degrade 1343 + // this to a LEFT join. We'll use WHERE to select matching rows 1344 + // later. 1345 + if ($has_null) { 1346 + $join_type = 'LEFT'; 1347 + } else { 1348 + $join_type = ''; 1349 + } 1350 + 1337 1351 $joins[] = qsprintf( 1338 1352 $conn, 1339 - 'JOIN %T %T ON %Q = %T.src AND %T.type = %d 1353 + '%Q JOIN %T %T ON %Q = %T.src AND %T.type = %d 1340 1354 AND %T.dst IN (%Ls)', 1355 + $join_type, 1341 1356 $edge_table, 1342 1357 $alias, 1343 1358 $phid_column, ··· 1377 1392 $full = array(); 1378 1393 $null = array(); 1379 1394 1395 + $op_null = PhabricatorQueryConstraint::OPERATOR_NULL; 1396 + $has_null = isset($constraints[$op_null]); 1397 + 1380 1398 foreach ($constraints as $operator => $list) { 1381 1399 $alias = $this->getEdgeLogicTableAlias($operator, $type); 1382 1400 switch ($operator) { ··· 1388 1406 break; 1389 1407 case PhabricatorQueryConstraint::OPERATOR_AND: 1390 1408 case PhabricatorQueryConstraint::OPERATOR_OR: 1409 + if ($has_null) { 1410 + $full[] = qsprintf( 1411 + $conn, 1412 + '%T.dst IS NOT NULL', 1413 + $alias); 1414 + } 1391 1415 break; 1392 1416 case PhabricatorQueryConstraint::OPERATOR_NULL: 1393 1417 $null[] = qsprintf(