Skip to content

Commit d54cf5b

Browse files
committed
feat(stemming): add stemming dictionary management support
- add `Stemming`, `StemmingDictionaries`, and `StemmingDictionary` classes - implement dictionary upsert and retrieve operations - add client support for stemming feature - add tests for dictionary operations
1 parent 126c5d8 commit d54cf5b

5 files changed

Lines changed: 195 additions & 0 deletions

File tree

src/Client.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,11 @@ class Client
7575
*/
7676
public Analytics $analytics;
7777

78+
/**
79+
* @var Stemming
80+
*/
81+
public Stemming $stemming;
82+
7883
/**
7984
* @var Conversations
8085
*/
@@ -108,6 +113,7 @@ public function __construct(array $config)
108113
$this->multiSearch = new MultiSearch($this->apiCall);
109114
$this->presets = new Presets($this->apiCall);
110115
$this->analytics = new Analytics($this->apiCall);
116+
$this->stemming = new Stemming($this->apiCall);
111117
$this->conversations = new Conversations($this->apiCall);
112118
}
113119

@@ -199,6 +205,14 @@ public function getAnalytics(): Analytics
199205
return $this->analytics;
200206
}
201207

208+
/**
209+
* @return Stemming
210+
*/
211+
public function getStemming(): Stemming
212+
{
213+
return $this->stemming;
214+
}
215+
202216
/**
203217
* @return Conversations
204218
*/

src/Stemming.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
namespace Typesense;
4+
5+
class Stemming
6+
{
7+
const RESOURCE_PATH = '/stemming';
8+
9+
private ApiCall $apiCall;
10+
11+
private StemmingDictionaries $typesenseDictionaries;
12+
13+
14+
public function __construct(ApiCall $apiCall)
15+
{
16+
$this->apiCall = $apiCall;
17+
}
18+
19+
public function dictionaries()
20+
{
21+
if (!isset($this->typesenseDictionaries)) {
22+
$this->typesenseDictionaries = new StemmingDictionaries($this->apiCall);
23+
}
24+
return $this->typesenseDictionaries;
25+
}
26+
}

src/StemmingDictionaries.php

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
<?php
2+
3+
namespace Typesense;
4+
5+
class StemmingDictionaries implements \ArrayAccess
6+
{
7+
const RESOURCE_PATH = '/stemming/dictionaries';
8+
9+
private ApiCall $apiCall;
10+
private $typesenseDictionaries = [];
11+
12+
public function __construct(ApiCall $apiCall)
13+
{
14+
$this->apiCall = $apiCall;
15+
}
16+
17+
public function __get($id)
18+
{
19+
if (!isset($this->typesenseDictionaries[$id])) {
20+
$this->typesenseDictionaries[$id] = new StemmingDictionary($id, $this->apiCall);
21+
}
22+
return $this->typesenseDictionaries[$id];
23+
}
24+
25+
public function upsert($id, $wordRootCombinations)
26+
{
27+
$dictionaryInJSONLFormat = is_array($wordRootCombinations) ? implode(
28+
"\n",
29+
array_map(
30+
static fn(array $wordRootCombo) => json_encode($wordRootCombo, JSON_THROW_ON_ERROR),
31+
$wordRootCombinations
32+
)
33+
) : $wordRootCombinations;
34+
35+
$resultsInJSONLFormat = $this->apiCall->post($this->endpoint_path("import"), $dictionaryInJSONLFormat, false, ["id" => $id]);
36+
37+
return is_array($wordRootCombinations) ? array_map(
38+
static function ($item) {
39+
return json_decode($item, true, 512, JSON_THROW_ON_ERROR);
40+
},
41+
array_filter(
42+
explode("\n", $resultsInJSONLFormat),
43+
'strlen'
44+
)
45+
) : $resultsInJSONLFormat;
46+
}
47+
48+
public function retrieve()
49+
{
50+
return $this->apiCall->get(StemmingDictionaries::RESOURCE_PATH, []);
51+
}
52+
53+
private function endpoint_path($operation = null)
54+
{
55+
return $operation === null ? self::RESOURCE_PATH : self::RESOURCE_PATH . "/" . encodeURIComponent($operation);
56+
}
57+
58+
/**
59+
* @inheritDoc
60+
*/
61+
public function offsetExists($offset): bool
62+
{
63+
return isset($this->typesenseDictionaries[$offset]);
64+
}
65+
66+
/**
67+
* @inheritDoc
68+
*/
69+
public function offsetGet($offset): StemmingDictionary
70+
{
71+
if (!isset($this->typesenseDictionaries[$offset])) {
72+
$this->typesenseDictionaries[$offset] = new StemmingDictionary($offset, $this->apiCall);
73+
}
74+
75+
return $this->typesenseDictionaries[$offset];
76+
}
77+
78+
/**
79+
* @inheritDoc
80+
*/
81+
public function offsetSet($offset, $value): void
82+
{
83+
$this->typesenseDictionaries[$offset] = $value;
84+
}
85+
86+
/**
87+
* @inheritDoc
88+
*/
89+
public function offsetUnset($offset): void
90+
{
91+
unset($this->typesenseDictionaries[$offset]);
92+
}
93+
}

src/StemmingDictionary.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?php
2+
3+
namespace Typesense;
4+
5+
class StemmingDictionary
6+
{
7+
private $id;
8+
private ApiCall $apiCall;
9+
10+
public function __construct(string $id, ApiCall $apiCall)
11+
{
12+
$this->id = $id;
13+
$this->apiCall = $apiCall;
14+
}
15+
16+
public function retrieve()
17+
{
18+
return $this->apiCall->get($this->endpointPath(), []);
19+
}
20+
21+
private function endpointPath()
22+
{
23+
return StemmingDictionaries::RESOURCE_PATH . '/' . encodeURIComponent($this->id);
24+
}
25+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
namespace Feature;
4+
5+
use Tests\TestCase;
6+
7+
class StemmingDictionariesTest extends TestCase
8+
{
9+
private $dictionaryId = 'test_dictionary';
10+
11+
private $dictionary = [
12+
["root" => "exampleRoot1", "word" => "exampleWord1"],
13+
["root" => "exampleRoot2", "word" => "exampleWord2"]
14+
];
15+
16+
private $dictionaryUpsertResponse = null;
17+
18+
public function testCanUpsertADictionary(): void
19+
{
20+
$this->dictionaryUpsertResponse = $this->client()->stemming->dictionaries()->upsert($this->dictionaryId, $this->dictionary);
21+
$this->assertEquals($this->dictionary, $this->dictionaryUpsertResponse);
22+
}
23+
24+
public function testCanRetrieveADictionary(): void
25+
{
26+
$returnData = $this->client()->stemming->dictionaries()[$this->dictionaryId]->retrieve();
27+
$this->assertEquals($returnData['id'], $this->dictionaryId);
28+
}
29+
30+
31+
public function testCanRetrieveAllRules(): void
32+
{
33+
$returnData = $this->client()->stemming->dictionaries()->retrieve();
34+
$this->assertCount(1, $returnData['dictionaries']);
35+
$this->assertEquals($returnData['dictionaries'][0], $this->dictionaryId);
36+
}
37+
}

0 commit comments

Comments
 (0)