@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 * This is a more formal version of @{class:PhabricatorEdgeQuery} that is used
5 * to expose edges to Conduit.
6 */
7final class PhabricatorEdgeObjectQuery
8 extends PhabricatorCursorPagedPolicyAwareQuery {
9
10 private $sourcePHIDs;
11 private $sourcePHIDType;
12 private $edgeTypes;
13 private $destinationPHIDs;
14
15 public function withSourcePHIDs(array $source_phids) {
16 $this->sourcePHIDs = $source_phids;
17 return $this;
18 }
19
20 public function withEdgeTypes(array $types) {
21 $this->edgeTypes = $types;
22 return $this;
23 }
24
25 public function withDestinationPHIDs(array $destination_phids) {
26 $this->destinationPHIDs = $destination_phids;
27 return $this;
28 }
29
30 protected function willExecute() {
31 $source_phids = $this->sourcePHIDs;
32
33 if (!$source_phids) {
34 throw new Exception(
35 pht(
36 'Edge object query must be executed with a nonempty list of '.
37 'source PHIDs.'));
38 }
39
40 $phid_item = null;
41 $phid_type = null;
42 foreach ($source_phids as $phid) {
43 $this_type = phid_get_type($phid);
44 if ($this_type == PhabricatorPHIDConstants::PHID_TYPE_UNKNOWN) {
45 throw new Exception(
46 pht(
47 'Source PHID "%s" in edge object query has unknown PHID type.',
48 $phid));
49 }
50
51 if ($phid_type === null) {
52 $phid_type = $this_type;
53 $phid_item = $phid;
54 continue;
55 }
56
57 if ($phid_type !== $this_type) {
58 throw new Exception(
59 pht(
60 'Two source PHIDs ("%s" and "%s") have different PHID types '.
61 '("%s" and "%s"). All PHIDs must be of the same type to execute '.
62 'an edge object query.',
63 $phid_item,
64 $phid,
65 $phid_type,
66 $this_type));
67 }
68 }
69
70 $this->sourcePHIDType = $phid_type;
71 }
72
73 protected function loadPage() {
74 $type = $this->sourcePHIDType;
75 $conn = PhabricatorEdgeConfig::establishConnection($type, 'r');
76 $table = PhabricatorEdgeConfig::TABLE_NAME_EDGE;
77 $rows = $this->loadStandardPageRowsWithConnection($conn, $table);
78
79 $result = array();
80 foreach ($rows as $row) {
81 $result[] = PhabricatorEdgeObject::newFromRow($row);
82 }
83
84 return $result;
85 }
86
87 protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
88 $parts = parent::buildWhereClauseParts($conn);
89
90 $parts[] = qsprintf(
91 $conn,
92 'src IN (%Ls)',
93 $this->sourcePHIDs);
94
95 $parts[] = qsprintf(
96 $conn,
97 'type IN (%Ls)',
98 $this->edgeTypes);
99
100 if ($this->destinationPHIDs !== null) {
101 $parts[] = qsprintf(
102 $conn,
103 'dst IN (%Ls)',
104 $this->destinationPHIDs);
105 }
106
107 return $parts;
108 }
109
110 public function getQueryApplicationClass() {
111 return null;
112 }
113
114 protected function getPrimaryTableAlias() {
115 return 'edge';
116 }
117
118 public function getOrderableColumns() {
119 return array(
120 'dateCreated' => array(
121 'table' => 'edge',
122 'column' => 'dateCreated',
123 'type' => 'int',
124 ),
125 'sequence' => array(
126 'table' => 'edge',
127 'column' => 'seq',
128 'type' => 'int',
129
130 // TODO: This is not actually unique, but we're just doing our best
131 // here.
132 'unique' => true,
133 ),
134 );
135 }
136
137 protected function getDefaultOrderVector() {
138 return array('dateCreated', 'sequence');
139 }
140
141 protected function newInternalCursorFromExternalCursor($cursor) {
142 list($epoch, $sequence) = $this->parseCursor($cursor);
143
144 // Instead of actually loading an edge, we're just making a fake edge
145 // with the properties the cursor describes.
146
147 $edge_object = PhabricatorEdgeObject::newFromRow(
148 array(
149 'dateCreated' => $epoch,
150 'seq' => $sequence,
151 ));
152
153 return id(new PhabricatorQueryCursor())
154 ->setObject($edge_object);
155 }
156
157 protected function newPagingMapFromPartialObject($object) {
158 return array(
159 'dateCreated' => $object->getDateCreated(),
160 'sequence' => $object->getSequence(),
161 );
162 }
163
164 protected function newExternalCursorStringForResult($object) {
165 return sprintf(
166 '%d_%d',
167 $object->getDateCreated(),
168 $object->getSequence());
169 }
170
171 private function parseCursor($cursor) {
172 if (!preg_match('/^\d+_\d+\z/', $cursor)) {
173 $this->throwCursorException(
174 pht(
175 'Expected edge cursor in the form "0123_6789", got "%s".',
176 $cursor));
177 }
178
179 return explode('_', $cursor);
180 }
181
182}