@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
3final class PhabricatorFactDatapointQuery extends Phobject {
4
5 private $facts;
6 private $objectPHIDs;
7 private $limit;
8
9 private $needVectors;
10
11 private $keyMap = array();
12 private $dimensionMap = array();
13
14 public function withFacts(array $facts) {
15 $this->facts = $facts;
16 return $this;
17 }
18
19 public function withObjectPHIDs(array $object_phids) {
20 $this->objectPHIDs = $object_phids;
21 return $this;
22 }
23
24 public function setLimit($limit) {
25 $this->limit = $limit;
26 return $this;
27 }
28
29 public function needVectors($need) {
30 $this->needVectors = $need;
31 return $this;
32 }
33
34 public function execute() {
35 $facts = mpull($this->facts, null, 'getKey');
36 if (!$facts) {
37 throw new Exception(pht('Executing a fact query requires facts.'));
38 }
39
40 $table_map = array();
41 foreach ($facts as $fact) {
42 $datapoint = $fact->newDatapoint();
43 $table = $datapoint->getTableName();
44
45 if (!isset($table_map[$table])) {
46 $table_map[$table] = array(
47 'table' => $datapoint,
48 'facts' => array(),
49 );
50 }
51
52 $table_map[$table]['facts'][] = $fact;
53 }
54
55 $rows = array();
56 foreach ($table_map as $spec) {
57 $rows[] = $this->executeWithTable($spec);
58 }
59 $rows = array_mergev($rows);
60
61 $key_unmap = array_flip($this->keyMap);
62 $dimension_unmap = array_flip($this->dimensionMap);
63
64 $groups = array();
65 $need_phids = array();
66 foreach ($rows as $row) {
67 $groups[$row['keyID']][] = $row;
68
69 $object_id = $row['objectID'];
70 if (!isset($dimension_unmap[$object_id])) {
71 $need_phids[$object_id] = $object_id;
72 }
73
74 $dimension_id = $row['dimensionID'];
75 if ($dimension_id && !isset($dimension_unmap[$dimension_id])) {
76 $need_phids[$dimension_id] = $dimension_id;
77 }
78 }
79
80 $dimension_unmap += id(new PhabricatorFactObjectDimension())
81 ->newDimensionUnmap($need_phids);
82
83 $results = array();
84 foreach ($groups as $key_id => $rows) {
85 $key = $key_unmap[$key_id];
86 $fact = $facts[$key];
87 $datapoint = $fact->newDatapoint();
88 foreach ($rows as $row) {
89 $dimension_id = $row['dimensionID'];
90 if ($dimension_id) {
91 if (!isset($dimension_unmap[$dimension_id])) {
92 continue;
93 } else {
94 $dimension_phid = $dimension_unmap[$dimension_id];
95 }
96 } else {
97 $dimension_phid = null;
98 }
99
100 $object_id = $row['objectID'];
101 if (!isset($dimension_unmap[$object_id])) {
102 continue;
103 } else {
104 $object_phid = $dimension_unmap[$object_id];
105 }
106
107 $result = array(
108 'key' => $key,
109 'objectPHID' => $object_phid,
110 'dimensionPHID' => $dimension_phid,
111 'value' => (int)$row['value'],
112 'epoch' => $row['epoch'],
113 );
114
115 if ($this->needVectors) {
116 $result['vector'] = $datapoint->newRawVector($result);
117 }
118
119 $results[] = $result;
120 }
121 }
122
123 return $results;
124 }
125
126 private function executeWithTable(array $spec) {
127 $table = $spec['table'];
128 $facts = $spec['facts'];
129 $conn = $table->establishConnection('r');
130
131 $fact_keys = mpull($facts, 'getKey');
132 $this->keyMap = id(new PhabricatorFactKeyDimension())
133 ->newDimensionMap($fact_keys);
134
135 if (!$this->keyMap) {
136 return array();
137 }
138
139 $where = array();
140
141 $where[] = qsprintf(
142 $conn,
143 'keyID IN (%Ld)',
144 $this->keyMap);
145
146 if ($this->objectPHIDs) {
147 $object_map = id(new PhabricatorFactObjectDimension())
148 ->newDimensionMap($this->objectPHIDs);
149 if (!$object_map) {
150 return array();
151 }
152
153 $this->dimensionMap = $object_map;
154
155 $where[] = qsprintf(
156 $conn,
157 'objectID IN (%Ld)',
158 $this->dimensionMap);
159 }
160
161 $where = qsprintf($conn, '%LA', $where);
162
163 if ($this->limit) {
164 $limit = qsprintf(
165 $conn,
166 'LIMIT %d',
167 $this->limit);
168 } else {
169 $limit = qsprintf($conn, '');
170 }
171
172 return queryfx_all(
173 $conn,
174 'SELECT keyID, objectID, dimensionID, value, epoch
175 FROM %T WHERE %Q %Q',
176 $table->getTableName(),
177 $where,
178 $limit);
179 }
180
181}