Skip to content

Commit

Permalink
Added v1 Queries
Browse files Browse the repository at this point in the history
  • Loading branch information
chrisreedio committed Apr 1, 2023
1 parent 05b988a commit 2f0e5c9
Show file tree
Hide file tree
Showing 4 changed files with 140 additions and 7 deletions.
35 changes: 32 additions & 3 deletions src/AzureDataExplorerApi.php
Expand Up @@ -14,6 +14,7 @@
use ReedTech\AzureDataExplorer\Interfaces\IngestModelInterface;
use ReedTech\AzureDataExplorer\Requests\FetchToken;
use ReedTech\AzureDataExplorer\Requests\QueryRequest;
use ReedTech\AzureDataExplorer\Requests\QueryV1Request;
use ReedTech\AzureDataExplorer\Requests\StreamingIngestRequest;
use ReflectionException;
use Saloon\Http\Response;
Expand Down Expand Up @@ -99,7 +100,7 @@ public function __construct(
public function fetchToken(bool $force = false): string
{
// TODO - Temporary 'in memory' caching of the token
if (! $force && $this->token !== null) {
if (!$force && $this->token !== null) {
return $this->token;
}

Expand Down Expand Up @@ -150,7 +151,35 @@ public function query(string|array $query): ?QueryResultsDTO

// Run the Data Explorer query
$response = $this->queryConnector->send(new QueryRequest($this->database, $query));
// dd($response->json());
// Handle Successful Response
try {
/** @var QueryResultsDTO $results */
$results = $response->dto();

return $results;
} catch (Exception $e) {
throw new DTOException('Unable to parse response into DTO');
}
}

/**
* Query Azure Data Explorer
*
* @param string|array $query
* @return QueryResultsDTO
*
* @throws Exception
* @throws ReflectionException
* @throws GuzzleException
* @throws SaloonException
*/
public function queryV1(string|array $query): ?QueryResultsDTO
{
// Returns true if ready to query, otherwise throws an exception
$this->validateSetup();

// Run the Data Explorer query
$response = $this->queryConnector->send(new QueryV1Request($this->database, $query));
// Handle Successful Response
try {
/** @var QueryResultsDTO $results */
Expand Down Expand Up @@ -187,7 +216,7 @@ public function ingest(IngestModelInterface $deModel): Response
private function validateSetup(): ?bool
{
if ($this->token === null) {
if (! $this->fetchToken()) {
if (!$this->fetchToken()) {
throw new AuthException('Failed to fetch token');
}
}
Expand Down
4 changes: 1 addition & 3 deletions src/Connectors/DataExplorerConnector.php
Expand Up @@ -38,7 +38,7 @@ public function resolveBaseUrl(): string
// $cluster = config('services.data_explorer.cluster');
// $region = config('services.data_explorer.region');

return 'https://'.$this->generateBaseURL();
return 'https://' . $this->generateBaseURL();
}

protected array $requests = [
Expand Down Expand Up @@ -69,8 +69,6 @@ public function defaultAuth(): Authenticator
// $tokenResponse = (new AuthenticationRequest())->send();
// $token = $tokenResponse->json('access_token');

// dd($token);

return new TokenAuthenticator($this->token);
}

Expand Down
32 changes: 31 additions & 1 deletion src/Data/QueryResultsDTO.php
Expand Up @@ -9,7 +9,7 @@ class QueryResultsDTO
public function __construct(
public array $columns,
public array $data,
public float $executionTime,
public float $executionTime = -1,
) {
}

Expand Down Expand Up @@ -47,4 +47,34 @@ public static function fromSaloon(Response $response): self

return new static($columns, $rows, $executionTime);
}

public static function parseV1(Response $response): self
{
$data = $response->json();

// Raw Data Extraction
$rawColumns = $data['Tables'][0]['Columns'];
$rawRows = $data['Tables'][0]['Rows'];
// $executionTime = $data['Statistics']['Query']['ExecutionTime'];

// Morph to intermediate state
$columns = collect($rawColumns)->pluck('ColumnName')->map(function ($column) {
// Column name manipulation
// $column = str_replace('ID', 'Id', $column);
// $column = Str::snake($column);

return trim($column);
})->all();

// Loop through each row and map the column names to the values
$rows = collect($rawRows)->map(function ($row) use ($columns) {
// Loop through each column and map the column name to the value
return collect($row)->map(function ($value, $key) use ($columns) {
// return [$columnName => $value]; // Map the column name to the value
return [$columns[$key] => trim($value)]; // Map the column name to the value
})->collapse()->all(); // Collapse the array to a single level
})->all();

return new static($columns, $rows);
}
}
76 changes: 76 additions & 0 deletions src/Requests/QueryV1Request.php
@@ -0,0 +1,76 @@
<?php

namespace ReedTech\AzureDataExplorer\Requests;

use ReedTech\AzureDataExplorer\Connectors\DataExplorerConnector;
use ReedTech\AzureDataExplorer\Data\QueryResultsDTO;
use Saloon\Contracts\Body\HasBody;
use Saloon\Contracts\Response as ContractsResponse;
use Saloon\Enums\Method;
use Saloon\Http\Request;
use Saloon\Http\Response;
use Saloon\Traits\Body\HasJsonBody;
use Saloon\Traits\Plugins\AcceptsJson;

class QueryV1Request extends Request implements HasBody
{
use AcceptsJson;
use HasJsonBody;

public function __construct(protected string $database, public string|array $kustoQuery)
{
}

/**
* The connector class.
*
* @var string|null
*/
protected ?string $connector = DataExplorerConnector::class;

/**
* The HTTP verb the request will use.
*
* @var Method
*/
protected Method $method = Method::POST;

/**
* The endpoint of the request.
*
* @return string
*/
public function resolveEndpoint(): string
{
return '/v1/rest/query';
}

public function defaultHeaders(): array
{
// $cluster = config('services.data_explorer.cluster');
// $region = config('services.data_explorer.region');

return [
// 'Content-Type' => 'application/json',
// 'Host' => "$cluster.$region.kusto.windows.net",
];
}

protected function defaultBody(): array
{
// Allows the user to pass in a single query string or an array of strings (multiple line queries)
$query = is_array($this->kustoQuery) ? implode("\n", $this->kustoQuery) : $this->kustoQuery;

return [
'csl' => $query,
// 'db' => config('services.data_explorer.db'),
'db' => $this->database,
];
}

// protected function castToDto(Response $response): object
public function createDtoFromResponse(ContractsResponse $response): mixed
{
return QueryResultsDTO::parseV1($response);
}
}

0 comments on commit 2f0e5c9

Please sign in to comment.