Skip to content

Commit

Permalink
Refactored table formatting with /cli endpoint (#84)
Browse files Browse the repository at this point in the history
Refactor to support automatic CLI table output for all Buddy plugins not just Show
  • Loading branch information
donhardman authored Dec 12, 2024
1 parent 403b1cd commit 60e85c4
Show file tree
Hide file tree
Showing 9 changed files with 230 additions and 105 deletions.
159 changes: 141 additions & 18 deletions src/ManticoreSearch/Response.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,36 @@ class Response {
*/
protected Struct $result;

/** @var bool */
protected bool $isRaw = false;

/**
* @var array<string,mixed> $columns
*/
protected array $columns;
protected array $columns = [];

/**
* @var array<string,mixed> $data
*/
protected array $data;
protected array $data = [];

/** @var bool */
protected bool $hasData = false;

/**
* @var string $error
*/
protected string $error = '';

/**
* @var ?string $error
* @var string $warning
*/
protected ?string $error;
protected string $warning = '';

/**
* @var int $total
*/
protected int $total = 0;

/**
* @var array<string,string> $meta
Expand All @@ -55,10 +71,17 @@ private function __construct(
/**
* @return ?string
*/
public function getError(): string|null {
public function getError(): ?string {
return $this->error;
}

/**
* @return ?string
*/
public function getWarning(): ?string {
return $this->warning;
}

/**
* @return string
*/
Expand All @@ -70,8 +93,36 @@ public function getBody(): string {
* @param callable $fn
* @return static
*/
public function filterResult(callable $fn): static {
$this->result->map($fn);
public function mapData(callable $fn): static {
$this->data = array_map($fn, $this->data);
return $this;
}

/**
* @param callable $fn
* @return static
*/
public function filterData(callable $fn): static {
$this->data = array_filter($this->data, $fn);
return $this;
}

/**
* @param array<string,mixed> $data
* @return static
*/
public function extendData(array $data): static {
$this->data = array_merge($this->data, $data);
return $this;
}

/**
* Apply some function to the whole result
* @param callable $fn
* @return static
*/
public function apply(callable $fn): static {
$this->result = $fn($this->result);
return $this;
}

Expand All @@ -83,9 +134,42 @@ public function getResult(): Struct {
if (!isset($this->result)) {
throw new ManticoreSearchResponseError('Trying to access result with no response created');
}
// We should replace data as result of applying modifier functions
// like filter, map or whatever
// @phpstan-ignore-next-line
if (isset($this->result[0]['data'])) {
$item = $this->result[0];
// @phpstan-ignore-next-line
$item['data'] = $this->data;
$result[0] = $item;
} else {
$this->result['data'] = $this->data;
}

return $this->result;
}

/**
* @return array<string,mixed>
*/
public function getData(): array {
return $this->data;
}

/**
* @return array<string,mixed>
*/
public function getColumns(): array {
return $this->columns;
}

/**
* @return int
*/
public function getTotal(): int {
return $this->total;
}

/**
* @param array<string,string> $meta
* @return static
Expand All @@ -108,7 +192,22 @@ public function getMeta(): array {
* @return bool
*/
public function hasError(): bool {
return isset($this->error);
return !!$this->error;
}

/**
* Check if we had warning on performing our request
* @return bool
*/
public function hasWarning(): bool {
return !!$this->warning;
}

/**
* @return bool
*/
public function hasData(): bool {
return $this->hasData;
}

/**
Expand Down Expand Up @@ -148,17 +247,41 @@ protected function parse(): void {
$data = $struct[0];
$struct = Struct::fromData($data, $struct->getBigIntFields());
}
if ($struct->hasKey('error') && is_string($struct['error']) && $struct['error'] !== '') {
$this->error = $struct['error'];
} else {
$this->error = null;
}
foreach (['columns', 'data'] as $prop) {
if (!$struct->hasKey($prop) || !is_array($struct[$prop])) {
continue;
}
$this->$prop = $struct[$prop];

$this->assign($struct, 'error')
->assign($struct, 'warning')
->assign($struct, 'total')
->assign($struct, 'data')
->assign($struct, 'columns');

// A bit tricky but we need to know if we have data or not
// For table formatter in current architecture
$this->hasData = $struct->hasKey('data');

// Check if this is type of response that is not our scheme
// in this case we just may proxy it as is without any extra
$this->isRaw = !$struct->hasKey('warning') &&
!$struct->hasKey('error') &&
!$struct->hasKey('total');
}

/**
* @return bool
*/
public function isRaw(): bool {
return $this->isRaw;
}

/**
* @param Struct<int|string, mixed> $struct
* @param string $key
* @return static
*/
public function assign(Struct $struct, string $key): static {
if ($struct->hasKey($key)) {
$this->$key = $struct[$key];
}
return $this;
}

/**
Expand Down
17 changes: 17 additions & 0 deletions src/Network/OutputFormat.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php declare(strict_types=1);

/*
Copyright (c) 2024, Manticore Software LTD (https://manticoresearch.com)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 3 or any later
version. You should have received a copy of the GPL license along with this
program; if you did not, you can find it at http://www.gnu.org/
*/

namespace Manticoresearch\Buddy\Core\Network;

enum OutputFormat {
case Table;
case Raw;
}
51 changes: 31 additions & 20 deletions src/Network/Request.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@
use Ds\Vector;
use Manticoresearch\Buddy\Core\Error\InvalidNetworkRequestError;
use Manticoresearch\Buddy\Core\Error\QueryParseError;
use Manticoresearch\Buddy\Core\ManticoreSearch\Endpoint as ManticoreEndpoint;
use Manticoresearch\Buddy\Core\ManticoreSearch\Endpoint;
use Manticoresearch\Buddy\Core\ManticoreSearch\MySQLTool;
use Manticoresearch\Buddy\Core\ManticoreSearch\RequestFormat;
use Manticoresearch\Buddy\Core\ManticoreSearch\Settings as ManticoreSettings;
use Manticoresearch\Buddy\Core\ManticoreSearch\Settings;
use Manticoresearch\Buddy\Core\Tool\Buddy;

final class Request {
Expand All @@ -33,9 +33,9 @@ final class Request {
public string $id;
public float $time;

public ManticoreEndpoint $endpointBundle;
public Endpoint $endpointBundle;
public RequestFormat $format;
public ManticoreSettings $settings;
public Settings $settings;
public string $path;
public string $error;
/** @var array<mixed> $errorBody */
Expand All @@ -61,9 +61,9 @@ public static function default(string $id = '0'): static {
$self = new static;
$self->id = $id;
$self->time = microtime(true);
$self->endpointBundle = ManticoreEndpoint::Sql;
$self->settings = ManticoreSettings::fromVector(new Vector());
$self->path = ManticoreEndpoint::Sql->value;
$self->endpointBundle = Endpoint::Sql;
$self->settings = Settings::fromVector(new Vector());
$self->path = Endpoint::Sql->value;
$self->format = RequestFormat::JSON;
$self->error = '';
$self->errorBody = [];
Expand Down Expand Up @@ -96,7 +96,7 @@ public static function fromString(string $data, string $id = '0'): static {
* payload:string,
* version:int,
* format:RequestFormat,
* endpointBundle:ManticoreEndpoint,
* endpointBundle:Endpoint,
* path:string
* } $data
* @param string $id
Expand Down Expand Up @@ -193,24 +193,24 @@ protected function parseOrFail(array $payload): static {
$path = '_bulk';
}
if (static::isElasticPath($path)) {
$endpointBundle = ManticoreEndpoint::Elastic;
$endpointBundle = Endpoint::Elastic;
} elseif (str_contains($path, '/_doc/') || str_contains($path, '/_create/')
|| str_ends_with($path, '/_doc')) {
// We don't differentiate elastic-like insert and replace queries here
// since this is irrelevant for the following Buddy processing logic
$endpointBundle = ManticoreEndpoint::Insert;
$endpointBundle = Endpoint::Insert;
} elseif (str_contains($path, '/_update/')) {
$endpointBundle = ManticoreEndpoint::Update;
$endpointBundle = Endpoint::Update;
} else {
$endpointBundle = match ($path) {
'bulk', '_bulk' => ManticoreEndpoint::Bulk,
'cli' => ManticoreEndpoint::Cli,
'cli_json' => ManticoreEndpoint::CliJson,
'search' => ManticoreEndpoint::Search,
'sql?mode=raw', 'sql', '' => ManticoreEndpoint::Sql,
'insert', 'replace' => ManticoreEndpoint::Insert,
'_license' => ManticoreEndpoint::Elastic,
'autocomplete' => ManticoreEndpoint::Autocomplete,
'bulk', '_bulk' => Endpoint::Bulk,
'cli' => Endpoint::Cli,
'cli_json' => Endpoint::CliJson,
'search' => Endpoint::Search,
'sql?mode=raw', 'sql', '' => Endpoint::Sql,
'insert', 'replace' => Endpoint::Insert,
'_license' => Endpoint::Elastic,
'autocomplete' => Endpoint::Autocomplete,
default => throw new InvalidNetworkRequestError(
"Do not know how to handle '{$payload['message']['path_query']}' path_query"
),
Expand All @@ -227,7 +227,7 @@ protected function parseOrFail(array $payload): static {
$this->format = $format;
$this->endpointBundle = $endpointBundle;
$this->mySQLTool = static::detectMySQLTool($payload['message']['body']);
$this->payload = (in_array($endpointBundle, [ManticoreEndpoint::Elastic, ManticoreEndpoint::Bulk]))
$this->payload = (in_array($endpointBundle, [Endpoint::Elastic, Endpoint::Bulk]))
? trim($payload['message']['body'])
: static::removeComments($payload['message']['body']);
$this->error = $payload['error']['message'];
Expand Down Expand Up @@ -339,4 +339,15 @@ static function (array $matches): string {
/** @var string $query */
return trim($query);
}

/**
* Validate if we should format the output in the Table way
* @return OutputFormat
*/
public function getOutputFormat(): OutputFormat {
return match ($this->endpointBundle) {
Endpoint::Cli => OutputFormat::Table,
default => OutputFormat::Raw,
};
}
}
10 changes: 0 additions & 10 deletions src/Network/Response.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
use Manticoresearch\Buddy\Core\Error\GenericError;
use Manticoresearch\Buddy\Core\ManticoreSearch\RequestFormat;
use Manticoresearch\Buddy\Core\Plugin\TableFormatter;
use Manticoresearch\Buddy\Core\Task\TaskResult;
use Manticoresearch\Buddy\Core\Tool\Buddy;

/** @package Manticoresearch\Buddy\Core\Network */
Expand Down Expand Up @@ -54,15 +53,6 @@ private static function checkForError(mixed $message): bool {
|| (is_string($message) && str_starts_with($message, TableFormatter::ERROR_PREFIX));
}

/**
* @param TaskResult $result
* @param RequestFormat $format
* @return static
*/
public static function fromResult(TaskResult $result, RequestFormat $format = RequestFormat::JSON): static {
return static::fromMessageAndMeta($result->getStruct(), $result->getMeta(), $format);
}

/**
* Create response from the message when we have no error and success in respond
* @see static::fromStringAndError()
Expand Down
Loading

0 comments on commit 60e85c4

Please sign in to comment.