Skip to content

Commit

Permalink
Fix history exports (#985)
Browse files Browse the repository at this point in the history
fixes #955
  • Loading branch information
nilmerg authored Mar 22, 2024
2 parents 018d45f + 95849d9 commit 06da58c
Show file tree
Hide file tree
Showing 10 changed files with 348 additions and 153 deletions.
79 changes: 3 additions & 76 deletions library/Icingadb/Data/CsvResultSet.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,82 +4,9 @@

namespace Icinga\Module\Icingadb\Data;

use DateTime;
use DateTimeZone;
use Icinga\Module\Icingadb\Redis\VolatileStateResults;
use ipl\Orm\Model;
use ipl\Orm\Query;
use ipl\Orm\ResultSet;

class CsvResultSet extends VolatileStateResults
class CsvResultSet extends ResultSet
{
protected $isCacheDisabled = true;

/**
* @return array<string, ?string>
*/
public function current(): array
{
return $this->extractKeysAndValues(parent::current());
}

protected function formatValue(string $key, $value): ?string
{
if (
$value
&& (
$key === 'id'
|| substr($key, -3) === '_id'
|| substr($key, -3) === '.id'
|| substr($key, -9) === '_checksum'
|| substr($key, -4) === '_bin'
)
) {
$value = bin2hex($value);
}

if (is_bool($value)) {
return $value ? 'true' : 'false';
} elseif (is_string($value)) {
return '"' . str_replace('"', '""', $value) . '"';
} elseif (is_array($value)) {
return '"' . implode(',', $value) . '"';
} elseif ($value instanceof DateTime) {
return $value->setTimezone(new DateTimeZone('UTC'))
->format('Y-m-d\TH:i:s.vP');
} else {
return $value;
}
}

protected function extractKeysAndValues(Model $model, string $path = ''): array
{
$keysAndValues = [];
foreach ($model as $key => $value) {
$keyPath = ($path ? $path . '.' : '') . $key;
if ($value instanceof Model) {
$keysAndValues += $this->extractKeysAndValues($value, $keyPath);
} else {
$keysAndValues[$keyPath] = $this->formatValue($key, $value);
}
}

return $keysAndValues;
}

public static function stream(Query $query): void
{
$query->setResultSetClass(__CLASS__);

foreach ($query as $i => $keysAndValues) {
if ($i === 0) {
echo implode(',', array_keys($keysAndValues));
}

echo "\r\n";

echo implode(',', array_values($keysAndValues));
}

exit;
}
use CsvResultSetUtils;
}
106 changes: 106 additions & 0 deletions library/Icingadb/Data/CsvResultSetUtils.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
<?php

/* Icinga DB Web | (c) 2024 Icinga GmbH | GPLv2 */

namespace Icinga\Module\Icingadb\Data;

use DateTime;
use DateTimeZone;
use Icinga\Module\Icingadb\Model\Host;
use Icinga\Module\Icingadb\Model\Service;
use ipl\Orm\Model;
use ipl\Orm\Query;

trait CsvResultSetUtils
{
/**
* @return array<string, ?string>
*/
public function current(): array
{
return $this->extractKeysAndValues(parent::current());
}

protected function formatValue(string $key, $value): ?string
{
if (
$value
&& (
$key === 'id'
|| substr($key, -3) === '_id'
|| substr($key, -3) === '.id'
|| substr($key, -9) === '_checksum'
|| substr($key, -4) === '_bin'
)
) {
$value = bin2hex($value);
}

if (is_bool($value)) {
return $value ? 'true' : 'false';
} elseif (is_string($value)) {
return '"' . str_replace('"', '""', $value) . '"';
} elseif (is_array($value)) {
return '"' . implode(',', $value) . '"';
} elseif ($value instanceof DateTime) {
return $value->setTimezone(new DateTimeZone('UTC'))
->format('Y-m-d\TH:i:s.vP');
} else {
return $value;
}
}

protected function extractKeysAndValues(Model $model, string $path = ''): array
{
$keysAndValues = [];
foreach ($model as $key => $value) {
$keyPath = ($path ? $path . '.' : '') . $key;
if ($value instanceof Model) {
$keysAndValues += $this->extractKeysAndValues($value, $keyPath);
} else {
$keysAndValues[$keyPath] = $this->formatValue($key, $value);
}
}

return $keysAndValues;
}

public static function stream(Query $query): void
{
if ($query->getModel() instanceof Host || $query->getModel() instanceof Service) {
$query->setResultSetClass(VolatileCsvResults::class);
} else {
$query->setResultSetClass(__CLASS__);
}

if ($query->hasLimit()) {
// Custom limits should still apply
$query->peekAhead(false);
$offset = $query->getOffset();
} else {
$query->limit(1000);
$query->peekAhead();
$offset = 0;
}

do {
$query->offset($offset);
$result = $query->execute()->disableCache();
foreach ($result as $i => $keysAndValues) {
if ($i === 0) {
echo implode(',', array_keys($keysAndValues));
}

echo "\r\n";

echo implode(',', array_values($keysAndValues));

JsonResultSet::giveMeMoreTime();
}

$offset += 1000;
} while ($result->hasMore());

exit;
}
}
74 changes: 3 additions & 71 deletions library/Icingadb/Data/JsonResultSet.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,77 +4,9 @@

namespace Icinga\Module\Icingadb\Data;

use DateTime;
use DateTimeZone;
use Icinga\Module\Icingadb\Redis\VolatileStateResults;
use Icinga\Util\Json;
use ipl\Orm\Model;
use ipl\Orm\Query;
use ipl\Orm\ResultSet;

class JsonResultSet extends VolatileStateResults
class JsonResultSet extends ResultSet
{
protected $isCacheDisabled = true;

/**
* @return array<string, ?string>
*/
public function current(): array
{
return $this->createObject(parent::current());
}

protected function formatValue(string $key, $value): ?string
{
if (
$value
&& (
$key === 'id'
|| substr($key, -3) === '_id'
|| substr($key, -3) === '.id'
|| substr($key, -9) === '_checksum'
|| substr($key, -4) === '_bin'
)
) {
$value = bin2hex($value);
}

if ($value instanceof DateTime) {
return $value->setTimezone(new DateTimeZone('UTC'))
->format('Y-m-d\TH:i:s.vP');
}

return $value;
}

protected function createObject(Model $model): array
{
$keysAndValues = [];
foreach ($model as $key => $value) {
if ($value instanceof Model) {
$keysAndValues[$key] = $this->createObject($value);
} else {
$keysAndValues[$key] = $this->formatValue($key, $value);
}
}

return $keysAndValues;
}

public static function stream(Query $query): void
{
$query->setResultSetClass(__CLASS__);

echo '[';
foreach ($query as $i => $object) {
if ($i > 0) {
echo ",\n";
}

echo Json::sanitize($object);
}

echo ']';

exit;
}
use JsonResultSetUtils;
}
Loading

0 comments on commit 06da58c

Please sign in to comment.