Skip to content

Commit 96e9126

Browse files
Spamerczclaude
andcommitted
feat(query): add script query
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 8e4d7d8 commit 96e9126

3 files changed

Lines changed: 131 additions & 0 deletions

File tree

doc/02-query-objects.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,21 @@ new \Spameri\ElasticQuery\Query\GeoBoundingBox(
490490

491491
---
492492

493+
##### Script Query
494+
Filter documents with a Painless boolean script.
495+
- Class: `\Spameri\ElasticQuery\Query\Script`
496+
- [Documentation](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-script-query.html)
497+
- [Implementation](https://github.com/Spameri/ElasticQuery/blob/master/src/Query/Script.php)
498+
499+
```php
500+
new \Spameri\ElasticQuery\Query\Script(
501+
source: "doc['amount'].value > params.threshold",
502+
params: ['threshold' => 100],
503+
);
504+
```
505+
506+
---
507+
493508
## Boolean Query Collections
494509

495510
These collections implement `LeafQueryInterface` and can be nested arbitrarily.

src/Query/Script.php

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
5+
namespace Spameri\ElasticQuery\Query;
6+
7+
/**
8+
* @see https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-script-query.html
9+
*/
10+
class Script implements \Spameri\ElasticQuery\Query\LeafQueryInterface
11+
{
12+
13+
/**
14+
* @param array<string, mixed> $params
15+
*/
16+
public function __construct(
17+
private string $source,
18+
private string $lang = 'painless',
19+
private array $params = [],
20+
)
21+
{
22+
}
23+
24+
25+
public function key(): string
26+
{
27+
return 'script_' . \md5($this->source);
28+
}
29+
30+
31+
/**
32+
* @return array<string, array<string, array<string, mixed>>>
33+
*/
34+
public function toArray(): array
35+
{
36+
$script = [
37+
'source' => $this->source,
38+
'lang' => $this->lang,
39+
];
40+
41+
if ($this->params !== []) {
42+
$script['params'] = $this->params;
43+
}
44+
45+
return [
46+
'script' => [
47+
'script' => $script,
48+
],
49+
];
50+
}
51+
52+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace SpameriTests\ElasticQuery\Query;
4+
5+
require_once __DIR__ . '/../../bootstrap.php';
6+
7+
8+
class Script extends \Tester\TestCase
9+
{
10+
11+
private const INDEX = 'spameri_test_query_script';
12+
13+
14+
public function setUp(): void
15+
{
16+
$ch = \curl_init();
17+
\curl_setopt($ch, \CURLOPT_URL, \ELASTICSEARCH_HOST . '/' . self::INDEX);
18+
\curl_setopt($ch, \CURLOPT_RETURNTRANSFER, 1);
19+
\curl_setopt($ch, \CURLOPT_CUSTOMREQUEST, 'PUT');
20+
\curl_setopt($ch, \CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
21+
22+
\curl_exec($ch);
23+
}
24+
25+
26+
public function testToArray(): void
27+
{
28+
$script = new \Spameri\ElasticQuery\Query\Script(
29+
source: "doc['amount'].value > params.threshold",
30+
params: ['threshold' => 100],
31+
);
32+
33+
$array = $script->toArray();
34+
35+
\Tester\Assert::same(
36+
"doc['amount'].value > params.threshold",
37+
$array['script']['script']['source'],
38+
);
39+
\Tester\Assert::same(['threshold' => 100], $array['script']['script']['params']);
40+
}
41+
42+
43+
public function testKey(): void
44+
{
45+
$script = new \Spameri\ElasticQuery\Query\Script('1 == 1');
46+
47+
\Tester\Assert::contains('script_', $script->key());
48+
}
49+
50+
51+
public function tearDown(): void
52+
{
53+
$ch = \curl_init();
54+
\curl_setopt($ch, \CURLOPT_URL, \ELASTICSEARCH_HOST . '/' . self::INDEX);
55+
\curl_setopt($ch, \CURLOPT_RETURNTRANSFER, 1);
56+
\curl_setopt($ch, \CURLOPT_CUSTOMREQUEST, 'DELETE');
57+
\curl_setopt($ch, \CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
58+
59+
\curl_exec($ch);
60+
}
61+
62+
}
63+
64+
(new Script())->run();

0 commit comments

Comments
 (0)