Skip to content

Commit c602ff7

Browse files
unit tests
1 parent da9f861 commit c602ff7

File tree

7 files changed

+221
-44
lines changed

7 files changed

+221
-44
lines changed

src/Helper/Esql/ChangePointCommand.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@
2323
class ChangePointCommand extends EsqlBase {
2424
private string $value;
2525
private string $key = "";
26-
private string $type_name = "type";
27-
private string $pvalue_name = "value";
26+
private string $type_name = "";
27+
private string $pvalue_name = "";
2828

2929
public function __construct(EsqlBase $parent, string $value)
3030
{

src/Helper/Esql/CompletionCommand.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@
2424
*/
2525
class CompletionCommand extends EsqlBase {
2626
private string $prompt;
27-
private array $named_prompt;
28-
private string $inference_id;
27+
private array $named_prompt = [];
28+
private string $inference_id = "";
2929

3030
public function __construct(EsqlBase $parent, array $prompt)
3131
{

src/Helper/Esql/EsqlBase.php

Lines changed: 37 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -19,39 +19,31 @@
1919
abstract class EsqlBase {
2020
private ?EsqlBase $parent = null;
2121

22+
protected function format_id(string $id, bool $allow_patterns = false): string
23+
{
24+
if ($allow_patterns && str_contains($id, "*")) {
25+
// patterns cannot be escaped
26+
return $id;
27+
}
28+
if (preg_match("/[A-Za-z_@][A-Za-z0-9_\\.]*/", $id)) {
29+
// all safe characters, so no need to escape
30+
return $id;
31+
}
32+
// apply escaping
33+
return "`" . str_replace("`", "``", $id) . "`";
34+
}
35+
2236
protected function format_kv(array $map): string
2337
{
2438
return implode(", ", array_map(
2539
function($k, $v) {
26-
return $k . "=" . json_encode($v);
40+
return $k . " = " . json_encode($v);
2741
},
2842
array_keys($map),
2943
$map,
3044
));
3145
}
3246

33-
public function render(): string
34-
{
35-
$query = "";
36-
if ($this->parent) {
37-
$query .= $this->parent->render() . "\n| ";
38-
}
39-
$query .= $this->render_internal();
40-
return $query;
41-
}
42-
43-
protected abstract function render_internal(): string;
44-
45-
public function __construct(?EsqlBase $parent)
46-
{
47-
$this->parent = $parent;
48-
}
49-
50-
public function __toString(): string
51-
{
52-
return $this->render() . "\n";
53-
}
54-
5547
protected function is_named_argument_list(array $args): bool {
5648
$named_count = array_sum(array_map('is_string', array_keys($args)));
5749
if ($named_count == sizeof($args)) {
@@ -63,20 +55,6 @@ protected function is_named_argument_list(array $args): bool {
6355
return false;
6456
}
6557

66-
protected function format_id(string $id, bool $allow_patterns = false): string
67-
{
68-
if ($allow_patterns && str_contains($id, "*")) {
69-
// patterns cannot be escaped
70-
return $id;
71-
}
72-
if (preg_match("/[A-Za-z_@][A-Za-z0-9_\\.]*/", $id)) {
73-
// all safe characters, so no need to escape
74-
return $id;
75-
}
76-
// apply escaping
77-
return "`" . str_replace("`", "``", $id) . "`";
78-
}
79-
8058
protected function is_forked(): bool
8159
{
8260
if (get_class($this) == "ForkCommand") {
@@ -88,6 +66,28 @@ protected function is_forked(): bool
8866
return false;
8967
}
9068

69+
public function __construct(?EsqlBase $parent)
70+
{
71+
$this->parent = $parent;
72+
}
73+
74+
public function render(): string
75+
{
76+
$query = "";
77+
if ($this->parent) {
78+
$query .= $this->parent->render() . "\n| ";
79+
}
80+
$query .= $this->render_internal();
81+
return $query;
82+
}
83+
84+
protected abstract function render_internal(): string;
85+
86+
public function __toString(): string
87+
{
88+
return $this->render() . "\n";
89+
}
90+
9191
/**
9292
* `CHANGE_POINT` detects spikes, dips, and change points in a metric.
9393
*

src/Helper/Esql/FromCommand.php

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,33 @@
1616

1717
class FromCommand extends EsqlBase {
1818
private array $indices;
19+
private array $metadata_fields = [];
1920

2021
public function __construct(array $indices)
2122
{
2223
$this->indices = $indices;
2324
}
2425

26+
/**
27+
* Continuation of the `FROM` source command.
28+
*
29+
* *param string ...$metadata_fields Metadata fields to retrieve, given as
30+
* positional arguments.
31+
*/
32+
public function metadata(string ...$metadata_fields): FromCommand
33+
{
34+
$this->metadata_fields = $metadata_fields;
35+
return $this;
36+
}
37+
2538
protected function render_internal(): string
2639
{
27-
return "FROM " . implode(", ", $this->indices);
40+
$s = "FROM " . implode(", ", $this->indices);
41+
if (sizeof($this->metadata_fields)) {
42+
$s .= " METADATA " . implode(
43+
", ", array_map(array($this, "format_id"), $this->metadata_fields)
44+
);
45+
}
46+
return $s;
2847
}
2948
}

src/Helper/Esql/Query.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public static function from(string ...$indices): FromCommand
4848
* query2 = ESQL.row(a=[1, 2])
4949
* query3 = ESQL.row(a=functions.round(1.23, 0))
5050
*/
51-
public static function row(string ...$params): RowCommand
51+
public static function row(mixed ...$params): RowCommand
5252
{
5353
return new RowCommand($params);
5454
}

src/Helper/Esql/SortCommand.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ protected function render_internal(): string
3434
$sorts = [];
3535
foreach ($this->columns as $column) {
3636
array_push($sorts, implode(
37-
" ", array_map(array($this, "format_id"), str_split($column))
37+
" ", array_map(array($this, "format_id"), explode(" ", $column))
3838
));
3939
}
4040
return "SORT " . implode(", ", $sorts);

tests/Helper/EsqlTest.php

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
<?php
2+
/**
3+
* Elasticsearch PHP Client
4+
*
5+
* @link https://github.com/elastic/elasticsearch-php
6+
* @copyright Copyright (c) Elasticsearch B.V (https://www.elastic.co)
7+
* @license https://opensource.org/licenses/MIT MIT License
8+
*
9+
* Licensed to Elasticsearch B.V under one or more agreements.
10+
* Elasticsearch B.V licenses this file to you under the MIT License.
11+
* See the LICENSE file in the project root for more information.
12+
*/
13+
declare(strict_types = 1);
14+
15+
namespace Elastic\Elasticsearch\Tests\Helper\Esql;
16+
17+
use Elastic\Elasticsearch\Helper\Esql\Query;
18+
use Elastic\Elasticsearch\Helper\Esql\Expression;
19+
use PHPUnit\Framework\TestCase;
20+
21+
class EsqlTest extends TestCase
22+
{
23+
public function testFrom(): void
24+
{
25+
$query = Query::from("employees");
26+
$this->assertEquals(
27+
"FROM employees\n",
28+
$query->__toString()
29+
);
30+
31+
$query = Query::from("<logs-{now/d}>");
32+
$this->assertEquals(
33+
"FROM <logs-{now/d}>\n",
34+
$query->__toString()
35+
);
36+
37+
$query = Query::from("employees-00001", "other-employees-*");
38+
$this->assertEquals(
39+
"FROM employees-00001, other-employees-*\n",
40+
$query->__toString()
41+
);
42+
43+
$query = Query::from("cluster_one:employees-00001", "cluster_two:other-employees-*");
44+
$this->assertEquals(
45+
"FROM cluster_one:employees-00001, cluster_two:other-employees-*\n",
46+
$query->__toString()
47+
);
48+
49+
$query = Query::from("employees")->metadata("_id");
50+
$this->assertEquals(
51+
"FROM employees METADATA _id\n",
52+
$query->__toString()
53+
);
54+
}
55+
56+
public function testRow(): void
57+
{
58+
$query = Query::row(a: 1, b: "two", c: null);
59+
$this->assertEquals(
60+
"ROW a = 1, b = \"two\", c = null\n",
61+
$query->__toString()
62+
);
63+
64+
$query = Query::row(a: [2, 1]);
65+
$this->assertEquals(
66+
"ROW a = [2,1]\n",
67+
$query->__toString()
68+
);
69+
70+
// $query = Query::row(a: Expression("ROUND(1.23, 0)"));
71+
// $this->assertEquals(
72+
// "ROW a = ROUND(1.23, 0)\n",
73+
// $query->__toString()
74+
// );
75+
}
76+
77+
public function testShow(): void
78+
{
79+
$query = Query::show("INFO");
80+
$this->assertEquals(
81+
"SHOW INFO\n",
82+
$query->__toString()
83+
);
84+
}
85+
86+
public function testChangePoint(): void
87+
{
88+
$query = Query::row(key: range(1, 25))
89+
->mv_expand("key")
90+
->eval(value: "CASE(key < 13, 0, 42)")
91+
->change_point("value")
92+
->on("key")
93+
->where("type IS NOT NULL");
94+
$this->assertEquals(<<<ESQL
95+
ROW key = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25]
96+
| MV_EXPAND key
97+
| EVAL value = CASE(key < 13, 0, 42)
98+
| CHANGE_POINT value ON key
99+
| WHERE type IS NOT NULL\n
100+
ESQL,
101+
$query->__toString()
102+
);
103+
}
104+
105+
public function testCompletion(): void
106+
{
107+
$query = Query::row(question: "What is Elasticsearch?")
108+
->completion("question")->with("test_completion_model")
109+
->keep("question", "completion");
110+
$this->assertEquals(<<<ESQL
111+
ROW question = "What is Elasticsearch?"
112+
| COMPLETION question WITH {"inference_id":"test_completion_model"}
113+
| KEEP question, completion\n
114+
ESQL,
115+
$query->__toString()
116+
);
117+
118+
$query = Query::row(question: "What is Elasticsearch?")
119+
->completion(answer: "question")->with("test_completion_model")
120+
->keep("question", "answer");
121+
$this->assertEquals(<<<ESQL
122+
ROW question = "What is Elasticsearch?"
123+
| COMPLETION answer = question WITH {"inference_id":"test_completion_model"}
124+
| KEEP question, answer\n
125+
ESQL,
126+
$query->__toString()
127+
);
128+
129+
$query = Query::from("movies")
130+
->sort("rating DESC")
131+
->limit(10)
132+
->eval(prompt: "CONCAT(\n" .
133+
" \"Summarize this movie using the following information: \\n\",\n" .
134+
" \"Title: \", title, \"\\n\",\n" .
135+
" \"Synopsis: \", synopsis, \"\\n\",\n" .
136+
" \"Actors: \", MV_CONCAT(actors, \", \"), \"\\n\",\n" .
137+
" )"
138+
)
139+
->completion(summary: "prompt")->with("test_completion_model")
140+
->keep("title", "summary", "rating");
141+
$this->assertEquals(<<<ESQL
142+
FROM movies
143+
| SORT rating DESC
144+
| LIMIT 10
145+
| EVAL prompt = CONCAT(
146+
"Summarize this movie using the following information: \\n",
147+
"Title: ", title, "\\n",
148+
"Synopsis: ", synopsis, "\\n",
149+
"Actors: ", MV_CONCAT(actors, ", "), "\\n",
150+
)
151+
| COMPLETION summary = prompt WITH {"inference_id":"test_completion_model"}
152+
| KEEP title, summary, rating\n
153+
ESQL,
154+
$query->__toString()
155+
);
156+
}
157+
}
158+

0 commit comments

Comments
 (0)