@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
at upstream/main 184 lines 4.7 kB view raw
1<?php 2 3/** 4 * @extends PhabricatorCursorPagedPolicyAwareQuery<DifferentialChangeset> 5 */ 6final class DifferentialChangesetQuery 7 extends PhabricatorCursorPagedPolicyAwareQuery { 8 9 private $ids; 10 private $phids; 11 private $diffPHIDs; 12 13 private $diffs; 14 15 private $needAttachToDiffs; 16 private $needHunks; 17 18 public function withIDs(array $ids) { 19 $this->ids = $ids; 20 return $this; 21 } 22 23 public function withPHIDs(array $phids) { 24 $this->phids = $phids; 25 return $this; 26 } 27 28 /** 29 * @param array<DifferentialDiff> $diffs 30 */ 31 public function withDiffs(array $diffs) { 32 assert_instances_of($diffs, DifferentialDiff::class); 33 $this->diffs = $diffs; 34 return $this; 35 } 36 37 public function withDiffPHIDs(array $phids) { 38 $this->diffPHIDs = $phids; 39 return $this; 40 } 41 42 public function needAttachToDiffs($attach) { 43 $this->needAttachToDiffs = $attach; 44 return $this; 45 } 46 47 public function needHunks($need) { 48 $this->needHunks = $need; 49 return $this; 50 } 51 52 protected function willExecute() { 53 // If we fail to load any changesets (which is possible in the case of an 54 // empty commit) we'll never call didFilterPage(). Attach empty changeset 55 // lists now so that we end up with the right result. 56 if ($this->needAttachToDiffs) { 57 foreach ($this->diffs as $diff) { 58 $diff->attachChangesets(array()); 59 } 60 } 61 } 62 63 public function newResultObject() { 64 return new DifferentialChangeset(); 65 } 66 67 protected function willFilterPage(array $changesets) { 68 // First, attach all the diffs we already have. We can just do this 69 // directly without worrying about querying for them. When we don't have 70 // a diff, record that we need to load it. 71 if ($this->diffs) { 72 $have_diffs = mpull($this->diffs, null, 'getID'); 73 } else { 74 $have_diffs = array(); 75 } 76 77 $must_load = array(); 78 foreach ($changesets as $key => $changeset) { 79 $diff_id = $changeset->getDiffID(); 80 if (isset($have_diffs[$diff_id])) { 81 $changeset->attachDiff($have_diffs[$diff_id]); 82 } else { 83 $must_load[$key] = $changeset; 84 } 85 } 86 87 // Load all the diffs we don't have. 88 $need_diff_ids = mpull($must_load, 'getDiffID'); 89 $more_diffs = array(); 90 if ($need_diff_ids) { 91 $more_diffs = id(new DifferentialDiffQuery()) 92 ->setViewer($this->getViewer()) 93 ->setParentQuery($this) 94 ->withIDs($need_diff_ids) 95 ->execute(); 96 $more_diffs = mpull($more_diffs, null, 'getID'); 97 } 98 99 // Attach the diffs we loaded. 100 foreach ($must_load as $key => $changeset) { 101 $diff_id = $changeset->getDiffID(); 102 if (isset($more_diffs[$diff_id])) { 103 $changeset->attachDiff($more_diffs[$diff_id]); 104 } else { 105 // We didn't have the diff, and could not load it (it does not exist, 106 // or we can't see it), so filter this result out. 107 unset($changesets[$key]); 108 } 109 } 110 111 return $changesets; 112 } 113 114 protected function didFilterPage(array $changesets) { 115 if ($this->needAttachToDiffs) { 116 $changeset_groups = mgroup($changesets, 'getDiffID'); 117 foreach ($this->diffs as $diff) { 118 $diff_changesets = idx($changeset_groups, $diff->getID(), array()); 119 $diff->attachChangesets($diff_changesets); 120 } 121 } 122 123 if ($this->needHunks) { 124 id(new DifferentialHunkQuery()) 125 ->setViewer($this->getViewer()) 126 ->setParentQuery($this) 127 ->withChangesets($changesets) 128 ->needAttachToChangesets(true) 129 ->execute(); 130 } 131 132 return $changesets; 133 } 134 135 protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { 136 $where = parent::buildWhereClauseParts($conn); 137 138 if ($this->diffs !== null) { 139 $where[] = qsprintf( 140 $conn, 141 'diffID IN (%Ld)', 142 mpull($this->diffs, 'getID')); 143 } 144 145 if ($this->ids !== null) { 146 $where[] = qsprintf( 147 $conn, 148 'id IN (%Ld)', 149 $this->ids); 150 } 151 152 if ($this->phids !== null) { 153 $where[] = qsprintf( 154 $conn, 155 'phid IN (%Ls)', 156 $this->phids); 157 } 158 159 if ($this->diffPHIDs !== null) { 160 $diff_ids = queryfx_all( 161 $conn, 162 'SELECT id FROM %R WHERE phid IN (%Ls)', 163 new DifferentialDiff(), 164 $this->diffPHIDs); 165 $diff_ids = ipull($diff_ids, 'id', null); 166 167 if (!$diff_ids) { 168 throw new PhabricatorEmptyQueryException(); 169 } 170 171 $where[] = qsprintf( 172 $conn, 173 'diffID IN (%Ld)', 174 $diff_ids); 175 } 176 177 return $where; 178 } 179 180 public function getQueryApplicationClass() { 181 return PhabricatorDifferentialApplication::class; 182 } 183 184}