@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<?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}