@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 recaptime-dev/main 181 lines 4.3 kB view raw
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}