Skip to content

Commit 46c55d8

Browse files
authored
Merge pull request #81 from tharropoulos/v28-changes
feat(stemming): add stemming dictionary management support
2 parents 126c5d8 + 38a8f65 commit 46c55d8

File tree

9 files changed

+213
-30
lines changed

9 files changed

+213
-30
lines changed

.github/workflows/tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ jobs:
88
runs-on: ubuntu-latest
99
services:
1010
typesense:
11-
image: typesense/typesense:27.0.rc21
11+
image: typesense/typesense:28.0.rc36
1212
ports:
1313
- 8108:8108/tcp
1414
volumes:

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/Conversations.php

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,6 @@ public function __construct(ApiCall $apiCall)
3737
$this->typesenseModels = new ConversationModels($this->apiCall);
3838
}
3939

40-
/**
41-
* @return array
42-
* @throws TypesenseClientError|HttpClientException
43-
*/
44-
public function retrieve(): array
45-
{
46-
return $this->apiCall->get(static::RESOURCE_PATH, []);
47-
}
48-
4940
/**
5041
* @return Models
5142
*/

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: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
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+
$response = $this->apiCall->get(StemmingDictionaries::RESOURCE_PATH, []);
51+
52+
// If response is null, return empty dictionaries structure
53+
if ($response === null) {
54+
return ['dictionaries' => []];
55+
}
56+
return $response;
57+
}
58+
59+
private function endpoint_path($operation = null)
60+
{
61+
return $operation === null ? self::RESOURCE_PATH : self::RESOURCE_PATH . "/" . encodeURIComponent($operation);
62+
}
63+
64+
/**
65+
* @inheritDoc
66+
*/
67+
public function offsetExists($offset): bool
68+
{
69+
return isset($this->typesenseDictionaries[$offset]);
70+
}
71+
72+
/**
73+
* @inheritDoc
74+
*/
75+
public function offsetGet($offset): StemmingDictionary
76+
{
77+
if (!isset($this->typesenseDictionaries[$offset])) {
78+
$this->typesenseDictionaries[$offset] = new StemmingDictionary($offset, $this->apiCall);
79+
}
80+
81+
return $this->typesenseDictionaries[$offset];
82+
}
83+
84+
/**
85+
* @inheritDoc
86+
*/
87+
public function offsetSet($offset, $value): void
88+
{
89+
$this->typesenseDictionaries[$offset] = $value;
90+
}
91+
92+
/**
93+
* @inheritDoc
94+
*/
95+
public function offsetUnset($offset): void
96+
{
97+
unset($this->typesenseDictionaries[$offset]);
98+
}
99+
}

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+
}

tests/Feature/ConversationTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,6 @@ public function testCanDeleteAConversation(): void
3737

3838
private function endPointPath(): string
3939
{
40-
return sprintf('%s/%s', ConversationsTest::RESOURCE_PATH, $this->id);
40+
return sprintf('%s/%s', "/conversations", $this->id);
4141
}
4242
}

tests/Feature/ConversationsTest.php

Lines changed: 0 additions & 19 deletions
This file was deleted.
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
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+
protected function setUp(): void
19+
{
20+
parent::setUp();
21+
22+
$this->client()->stemming->dictionaries()->upsert(
23+
$this->dictionaryId,
24+
$this->dictionary
25+
);
26+
}
27+
28+
public function testCanUpsertADictionary(): void
29+
{
30+
$this->dictionaryUpsertResponse = $this->client()->stemming->dictionaries()->upsert($this->dictionaryId, $this->dictionary);
31+
$this->assertEquals($this->dictionary, $this->dictionaryUpsertResponse);
32+
}
33+
34+
public function testCanRetrieveADictionary(): void
35+
{
36+
$returnData = $this->client()->stemming->dictionaries()[$this->dictionaryId]->retrieve();
37+
$this->assertEquals($returnData['id'], $this->dictionaryId);
38+
}
39+
40+
41+
public function testCanRetrieveAllDicitionaries(): void
42+
{
43+
$returnData = $this->client()->stemming->dictionaries()->retrieve();
44+
$this->assertCount(1, $returnData['dictionaries']);
45+
$this->assertEquals($returnData['dictionaries'][0], $this->dictionaryId);
46+
}
47+
}

0 commit comments

Comments
 (0)