diff --git a/src/Analytics.php b/src/Analytics.php index 2f161dd1..4591de04 100644 --- a/src/Analytics.php +++ b/src/Analytics.php @@ -32,4 +32,4 @@ public function events() } return $this->events; } -} +} \ No newline at end of file diff --git a/src/AnalyticsEvents.php b/src/AnalyticsEvents.php index 6b7180bf..6b2ad484 100644 --- a/src/AnalyticsEvents.php +++ b/src/AnalyticsEvents.php @@ -4,6 +4,8 @@ /** * Class AnalyticsEvents + * + * Implements the updated analytics events API for Typesense + * * @package \Typesense */ @@ -11,37 +13,33 @@ class AnalyticsEvents { const RESOURCE_PATH = '/analytics/events'; - /** - * @var ApiCall - */ private ApiCall $apiCall; - /** - * AnalyticsEvents constructor. - * - * @param ApiCall $apiCall - */ public function __construct(ApiCall $apiCall) { $this->apiCall = $apiCall; } /** - * @param array $params - * - * @return array + * Create an analytics event + * + * @param array $params Event parameters including name, event_type, and data + * @return array Response from the API * @throws TypesenseClientError|HttpClientException */ - public function create($params) + public function create(array $params) { - return $this->apiCall->post($this->endpoint_path(), $params); + return $this->apiCall->post(self::RESOURCE_PATH, $params); } /** - * @return string + * Retrieve analytics events + * + * @param array $params Query parameters + * @return array Response from the API */ - private function endpoint_path($operation = null) + public function retrieve(array $params = []) { - return self::RESOURCE_PATH . ($operation === null ? '' : "/$operation"); + return $this->apiCall->get(self::RESOURCE_PATH, $params); } -} +} \ No newline at end of file diff --git a/src/AnalyticsEventsV1.php b/src/AnalyticsEventsV1.php new file mode 100644 index 00000000..407e1a6b --- /dev/null +++ b/src/AnalyticsEventsV1.php @@ -0,0 +1,47 @@ +apiCall = $apiCall; + } + + /** + * @param array $params + * + * @return array + * @throws TypesenseClientError|HttpClientException + */ + public function create($params) + { + return $this->apiCall->post($this->endpoint_path(), $params); + } + + /** + * @return string + */ + private function endpoint_path($operation = null) + { + return self::RESOURCE_PATH . ($operation === null ? '' : "/$operation"); + } +} diff --git a/src/AnalyticsRule.php b/src/AnalyticsRule.php index a574e301..2c303960 100644 --- a/src/AnalyticsRule.php +++ b/src/AnalyticsRule.php @@ -4,27 +4,48 @@ class AnalyticsRule { - private $ruleName; + private string $ruleName; private ApiCall $apiCall; public function __construct(string $ruleName, ApiCall $apiCall) { $this->ruleName = $ruleName; - $this->apiCall = $apiCall; + $this->apiCall = $apiCall; } + /** + * Retrieve a specific analytics rule + * + * @return array Response from the API + */ public function retrieve() { return $this->apiCall->get($this->endpointPath(), []); } + /** + * Delete a specific analytics rule + * + * @return array Response from the API + */ public function delete() { return $this->apiCall->delete($this->endpointPath()); } + /** + * Update a specific analytics rule + * + * @param array $params Rule parameters + * @return array Response from the API + */ + public function update(array $params) + { + return $this->apiCall->put($this->endpointPath(), $params); + } + private function endpointPath() { return AnalyticsRules::RESOURCE_PATH . '/' . encodeURIComponent($this->ruleName); } -} +} \ No newline at end of file diff --git a/src/AnalyticsRuleV1.php b/src/AnalyticsRuleV1.php new file mode 100644 index 00000000..f4b52b52 --- /dev/null +++ b/src/AnalyticsRuleV1.php @@ -0,0 +1,30 @@ +ruleName = $ruleName; + $this->apiCall = $apiCall; + } + + public function retrieve() + { + return $this->apiCall->get($this->endpointPath(), []); + } + + public function delete() + { + return $this->apiCall->delete($this->endpointPath()); + } + + private function endpointPath() + { + return AnalyticsRulesV1::RESOURCE_PATH . '/' . encodeURIComponent($this->ruleName); + } +} diff --git a/src/AnalyticsRules.php b/src/AnalyticsRules.php index 444d1cb2..199b2c6b 100644 --- a/src/AnalyticsRules.php +++ b/src/AnalyticsRules.php @@ -7,69 +7,64 @@ class AnalyticsRules implements \ArrayAccess const RESOURCE_PATH = '/analytics/rules'; private ApiCall $apiCall; - private $analyticsRules = []; public function __construct(ApiCall $apiCall) { $this->apiCall = $apiCall; } - public function __get($ruleName) - { - if (!isset($this->analyticsRules[$ruleName])) { - $this->analyticsRules[$ruleName] = new AnalyticsRule($ruleName, $this->apiCall); - } - return $this->analyticsRules[$ruleName]; - } - - public function upsert($ruleName, $params) + /** + * Create multiple analytics rules + * + * @param array $rules Array of rule objects + * @return array Response from the API + */ + public function create(array $rules) { - return $this->apiCall->put($this->endpoint_path($ruleName), $params); + return $this->apiCall->post(self::RESOURCE_PATH, $rules); } + /** + * Retrieve all analytics rules + * + * @return array Response from the API + */ public function retrieve() { - return $this->apiCall->get($this->endpoint_path(), []); + return $this->apiCall->get(self::RESOURCE_PATH, []); } - private function endpoint_path($operation = null) + /** + * Get a specific rule by name + * + * @param string $ruleName + * @return AnalyticsRule + */ + public function __get($ruleName) { - return self::RESOURCE_PATH . ($operation === null ? '' : "/" . encodeURIComponent($operation)); + return new AnalyticsRule($ruleName, $this->apiCall); } /** - * @inheritDoc + * ArrayAccess implementation for backwards compatibility */ public function offsetExists($offset): bool { - return isset($this->analyticsRules[$offset]); + return true; // Rules can be accessed by name } - /** - * @inheritDoc - */ public function offsetGet($offset): AnalyticsRule { - if (!isset($this->analyticsRules[$offset])) { - $this->analyticsRules[$offset] = new AnalyticsRule($offset, $this->apiCall); - } - - return $this->analyticsRules[$offset]; + return new AnalyticsRule($offset, $this->apiCall); } - /** - * @inheritDoc - */ public function offsetSet($offset, $value): void { - $this->analyticsRules[$offset] = $value; + // Not implemented for read-only access } - /** - * @inheritDoc - */ public function offsetUnset($offset): void { - unset($this->analyticsRules[$offset]); + // Not implemented for read-only access } -} +} \ No newline at end of file diff --git a/src/AnalyticsRulesV1.php b/src/AnalyticsRulesV1.php new file mode 100644 index 00000000..59924fc7 --- /dev/null +++ b/src/AnalyticsRulesV1.php @@ -0,0 +1,75 @@ +apiCall = $apiCall; + } + + public function __get($ruleName) + { + if (!isset($this->analyticsRules[$ruleName])) { + $this->analyticsRules[$ruleName] = new AnalyticsRuleV1($ruleName, $this->apiCall); + } + return $this->analyticsRules[$ruleName]; + } + + public function upsert($ruleName, $params) + { + return $this->apiCall->put($this->endpoint_path($ruleName), $params); + } + + public function retrieve() + { + return $this->apiCall->get($this->endpoint_path(), []); + } + + private function endpoint_path($operation = null) + { + return self::RESOURCE_PATH . ($operation === null ? '' : "/" . encodeURIComponent($operation)); + } + + /** + * @inheritDoc + */ + public function offsetExists($offset): bool + { + return isset($this->analyticsRules[$offset]); + } + + /** + * @inheritDoc + */ + public function offsetGet($offset): AnalyticsRuleV1 + { + if (!isset($this->analyticsRules[$offset])) { + $this->analyticsRules[$offset] = new AnalyticsRuleV1($offset, $this->apiCall); + } + + return $this->analyticsRules[$offset]; + } + + /** + * @inheritDoc + */ + public function offsetSet($offset, $value): void + { + $this->analyticsRules[$offset] = $value; + } + + /** + * @inheritDoc + */ + public function offsetUnset($offset): void + { + unset($this->analyticsRules[$offset]); + } +} diff --git a/src/AnalyticsV1.php b/src/AnalyticsV1.php new file mode 100644 index 00000000..371a1bb0 --- /dev/null +++ b/src/AnalyticsV1.php @@ -0,0 +1,35 @@ +apiCall = $apiCall; + } + + public function rules() + { + if (!isset($this->rules)) { + $this->rules = new AnalyticsRulesV1($this->apiCall); + } + return $this->rules; + } + + public function events() + { + if (!isset($this->events)) { + $this->events = new AnalyticsEventsV1($this->apiCall); + } + return $this->events; + } +} diff --git a/src/Client.php b/src/Client.php index a4f8a084..277c1f41 100644 --- a/src/Client.php +++ b/src/Client.php @@ -70,6 +70,11 @@ class Client */ public Presets $presets; + /** + * @var AnalyticsV1 + */ + public AnalyticsV1 $analyticsV1; + /** * @var Analytics */ @@ -118,6 +123,7 @@ public function __construct(array $config) $this->multiSearch = new MultiSearch($this->apiCall); $this->presets = new Presets($this->apiCall); $this->analytics = new Analytics($this->apiCall); + $this->analyticsV1 = new AnalyticsV1($this->apiCall); $this->stemming = new Stemming($this->apiCall); $this->conversations = new Conversations($this->apiCall); $this->nlSearchModels = new NLSearchModels($this->apiCall); diff --git a/tests/Feature/AnalyticsEventsTest.php b/tests/Feature/AnalyticsEventsTest.php index c1fa70d6..3f9ff3e8 100644 --- a/tests/Feature/AnalyticsEventsTest.php +++ b/tests/Feature/AnalyticsEventsTest.php @@ -3,69 +3,166 @@ namespace Feature; use Tests\TestCase; +use Exception; class AnalyticsEventsTest extends TestCase { - private $ruleName = 'product_queries_aggregation'; + private $ruleName = 'test__rule'; + private $ruleConfiguration; protected function setUp(): void { parent::setUp(); - $this->client()->collections->create([ - "name" => "products", - "fields" => [ - [ - "name" => "title", - "type" => "string" - ], - [ - "name" => "popularity", - "type" => "int32", - "optional" => true - ] - ] - ]); - $this->client()->analytics->rules()->upsert($this->ruleName, [ - "name" => "products_popularity", + + $this->ruleConfiguration = [ + "name" => $this->ruleName, "type" => "counter", + "collection" => "test_products", + "event_type" => "click", + "rule_tag" => "test_tag", "params" => [ - "source" => [ - "collections" => [ - "products" - ], - "events" => [ - [ - "type" => "click", - "weight" => 1, - "name" => "products_click_event" - ] - ] - ], - "destination" => [ - "collection" => "products", - "counter_field" => "popularity" - ] + "counter_field" => "popularity", + "weight" => 1 ] - ]); + ]; + + if (!$this->isV30OrAbove()) { + $this->markTestSkipped('New Analytics API is not supported in Typesense 29.0 and below'); + } + + try { + $this->client()->collections->create([ + 'name' => 'test_products', + 'fields' => [ + ['name' => 'company_name', 'type' => 'string'], + ['name' => 'num_employees', 'type' => 'int32'], + ['name' => 'country', 'type' => 'string', 'facet' => true], + ['name' => 'popularity', 'type' => 'int32', 'optional' => true] + ], + 'default_sorting_field' => 'num_employees' + ]); + } catch (Exception $e) { + } + + try { + $this->client()->analytics->rules()->create([$this->ruleConfiguration]); + } catch (Exception $e) { + } } protected function tearDown(): void { - parent::tearDown(); - $this->client()->analytics->rules()->{'product_queries_aggregation'}->delete(); + if ($this->isV30OrAbove()) { + try { + $rules = $this->client()->analytics->rules()->retrieve(); + if (is_array($rules)) { + foreach ($rules as $rule) { + if (strpos($rule['name'], 'test__') === 0) { + try { + $this->client()->analytics->rules()[$rule['name']]->delete(); + } catch (Exception $e) { + } + } + } + } + } catch (Exception $e) { + } + + try { + $this->client()->collections['test_products']->delete(); + } catch (Exception $e) { + } + } + } + + public function testCanCreateEventsWithAPI(): void + { + $event = [ + "name" => $this->ruleName, + "event_type" => "click", + "data" => [ + "doc_ids" => ["1", "2"], + "user_id" => "test_user" + ] + ]; + + $response = $this->client()->analytics->events()->create($event); + $this->assertIsArray($response); } - public function testCanCreateAnEvent(): void + public function testCanCreateMultipleEventsWithAPI(): void { - $response = $this->client()->analytics->events()->create([ - "type" => "click", - "name" => "products_click_event", + $event1 = [ + "name" => $this->ruleName, + "event_type" => "click", + "data" => [ + "doc_id" => "1", + "user_id" => "test_user_1" + ] + ]; + + $event2 = [ + "name" => $this->ruleName, + "event_type" => "click", "data" => [ - "q" => "nike shoes", - "doc_id" => "1024", - "user_id" => "111112" + "doc_id" => "2", + "user_id" => "test_user_2" ] + ]; + + $response1 = $this->client()->analytics->events()->create($event1); + $this->assertIsArray($response1); + + $response2 = $this->client()->analytics->events()->create($event2); + $this->assertIsArray($response2); + } + + public function testCanRetrieveEventsWithAPI(): void + { + $event = [ + "name" => $this->ruleName, + "event_type" => "click", + "data" => [ + "doc_id" => "1", + "user_id" => "test_user" + ] + ]; + + $this->client()->analytics->events()->create($event); + + $response = $this->client()->analytics->events()->retrieve([ + 'user_id' => 'test_user', + 'name' => $this->ruleName, + 'n'=> 10 ]); - $this->assertTrue($response['ok']); + + $this->assertIsArray($response); + } + + public function testCanCreateEventWithDifferentEventTypes(): void + { + $clickEvent = [ + "name" => $this->ruleName, + "event_type" => "click", + "data" => [ + "doc_id" => "1", + "user_id" => "test_user" + ] + ]; + + $conversionEvent = [ + "name" => $this->ruleName, + "event_type" => "conversion", + "data" => [ + "doc_id" => "1", + "user_id" => "test_user" + ] + ]; + + $clickResponse = $this->client()->analytics->events()->create($clickEvent); + $this->assertIsArray($clickResponse); + + $conversionResponse = $this->client()->analytics->events()->create($conversionEvent); + $this->assertIsArray($conversionResponse); } -} +} \ No newline at end of file diff --git a/tests/Feature/AnalyticsEventsV1Test.php b/tests/Feature/AnalyticsEventsV1Test.php new file mode 100644 index 00000000..12c809c7 --- /dev/null +++ b/tests/Feature/AnalyticsEventsV1Test.php @@ -0,0 +1,83 @@ +isV30OrAbove()) { + $this->markTestSkipped('Analytics is deprecated in Typesense v30+'); + } + + $this->client()->collections->create([ + "name" => "products", + "fields" => [ + [ + "name" => "title", + "type" => "string" + ], + [ + "name" => "popularity", + "type" => "int32", + "optional" => true + ] + ] + ]); + $this->client()->analyticsV1->rules()->upsert($this->ruleName, [ + "name" => "products_popularity", + "type" => "counter", + "params" => [ + "source" => [ + "collections" => [ + "products" + ], + "events" => [ + [ + "type" => "click", + "weight" => 1, + "name" => "products_click_event" + ] + ] + ], + "destination" => [ + "collection" => "products", + "counter_field" => "popularity" + ] + ] + ]); + } + + protected function tearDown(): void + { + parent::tearDown(); + + if (!$this->isV30OrAbove()) { + try { + $this->client()->analyticsV1->rules()->{'product_queries_aggregation'}->delete(); + } catch (Exception $e) { + } + } + } + + public function testCanCreateAnEvent(): void + { + $response = $this->client()->analyticsV1->events()->create([ + "type" => "click", + "name" => "products_click_event", + "data" => [ + "q" => "nike shoes", + "doc_id" => "1024", + "user_id" => "111112" + ] + ]); + $this->assertTrue($response['ok']); + } +} diff --git a/tests/Feature/AnalyticsRulesTest.php b/tests/Feature/AnalyticsRulesTest.php index 882ef896..9709bf60 100644 --- a/tests/Feature/AnalyticsRulesTest.php +++ b/tests/Feature/AnalyticsRulesTest.php @@ -3,63 +3,173 @@ namespace Feature; use Tests\TestCase; -use Typesense\Exceptions\ObjectNotFound; +use Typesense\Exceptions\RequestMalformed; +use Exception; class AnalyticsRulesTest extends TestCase { - private $ruleName = 'test_rule'; - private $ruleConfiguration = [ - "type" => "popular_queries", - "params" => [ - "source" => [ - "collections" => ["products"] - ], - "destination" => [ - "collection" => "product_queries" - ], - "expand_query" => false, - "limit" => 1000 - ] - ]; - private $ruleUpsertResponse = null; + private $ruleName = 'test__rule'; + private $ruleConfiguration; protected function setUp(): void { parent::setUp(); - $this->ruleUpsertResponse = $this->client()->analytics->rules()->upsert($this->ruleName, $this->ruleConfiguration); + + $this->ruleConfiguration = [ + "name" => $this->ruleName, + "type" => "counter", + "collection" => "test_products", + "event_type" => "click", + "rule_tag" => "test_tag", + "params" => [ + "counter_field" => "popularity", + "weight" => 1 + ] + ]; + + if (!$this->isV30OrAbove()) { + $this->markTestSkipped('New Analytics API is not supported in Typesense 9.0 and below'); + } + + try { + $this->client()->collections->create([ + 'name' => 'test_products', + 'fields' => [ + ['name' => 'company_name', 'type' => 'string'], + ['name' => 'num_employees', 'type' => 'int32'], + ['name' => 'country', 'type' => 'string', 'facet' => true], + ['name' => 'popularity', 'type' => 'int32', 'optional' => true] + ], + 'default_sorting_field' => 'num_employees' + ]); + } catch (Exception $e) { + } + + try { + $this->client()->analytics->rules()->create([$this->ruleConfiguration]); + } catch (Exception $e) { + } } protected function tearDown(): void { - $rules = $this->client()->analytics->rules()->retrieve(); - foreach ($rules['rules'] as $rule) { - $this->client()->analytics->rules()->{$rule['name']}->delete(); + if ($this->isV30OrAbove()) { + try { + $rules = $this->client()->analytics->rules()->retrieve(); + if (is_array($rules)) { + foreach ($rules as $rule) { + if (strpos($rule['name'], 'test__') === 0) { + try { + $this->client()->analytics->rules()[$rule['name']]->delete(); + } catch (Exception $e) { + } + } + } + } + } catch (Exception $e) { + } + + try { + $this->client()->collections['test_products']->delete(); + } catch (Exception $e) { + } } } - public function testCanUpsertARule(): void + public function testCanCreateRulesWithAPI(): void { - $this->assertEquals($this->ruleName, $this->ruleUpsertResponse['name']); + $rules = [ + [ + "name" => "test_rule_1", + "type" => "counter", + "collection" => "test_products", + "event_type" => "click", + "rule_tag" => "test_tag", + "params" => [ + "counter_field" => "popularity", + "weight" => 1 + ] + ], + [ + "name" => "test_rule_2", + "type" => "counter", + "collection" => "test_products", + "event_type" => "conversion", + "rule_tag" => "test_tag", + "params" => [ + "counter_field" => "popularity", + "weight" => 2 + ] + ] + ]; + + $response = $this->client()->analytics->rules()->create($rules); + $this->assertIsArray($response); + + $allRules = $this->client()->analytics->rules()->retrieve(); + $this->assertIsArray($allRules); + + $ruleNames = array_column($allRules, 'name'); + $this->assertContains('test_rule_1', $ruleNames); + $this->assertContains('test_rule_2', $ruleNames); } - public function testCanRetrieveARule(): void + public function testCanRetrieveARuleWithAPI(): void { $returnData = $this->client()->analytics->rules()[$this->ruleName]->retrieve(); - $this->assertEquals($returnData['name'], $this->ruleName); + $this->assertEquals($this->ruleName, $returnData['name']); + $this->assertEquals('counter', $returnData['type']); + $this->assertEquals('test_products', $returnData['collection']); } - public function testCanDeleteARule(): void + public function testCanUpdateARuleWithAPI(): void + { + $updateParams = [ + "type" => "counter", + "collection" => "test_products", + "event_type" => "click", + "rule_tag" => "updated_tag", + "params" => [ + "counter_field" => "popularity", + "weight" => 5 + ] + ]; + + $response = $this->client()->analytics->rules()[$this->ruleName]->update($updateParams); + $this->assertEquals($this->ruleName, $response['name']); + $this->assertEquals('updated_tag', $response['rule_tag']); + $this->assertEquals(5, $response['params']['weight']); + } + + public function testCanDeleteARuleWithAPI(): void { $returnData = $this->client()->analytics->rules()[$this->ruleName]->delete(); - $this->assertEquals($returnData['name'], $this->ruleName); + $this->assertEquals($this->ruleName, $returnData['name']); - $this->expectException(ObjectNotFound::class); + $this->expectException(RequestMalformed::class); $this->client()->analytics->rules()[$this->ruleName]->retrieve(); } - public function testCanRetrieveAllRules(): void + public function testCanRetrieveAllRulesWithAPI(): void { $returnData = $this->client()->analytics->rules()->retrieve(); - $this->assertCount(1, $returnData['rules']); + $this->assertIsArray($returnData); + $this->assertGreaterThanOrEqual(1, count($returnData)); + + $ruleNames = array_column($returnData, 'name'); + $this->assertContains('test__rule', $ruleNames); + $this->assertContains('test_rule_1', $ruleNames); + $this->assertContains('test_rule_2', $ruleNames); + } + + public function testArrayAccessCompatibility(): void + { + $rule = $this->client()->analytics->rules()[$this->ruleName]; + $this->assertInstanceOf('Typesense\AnalyticsRule', $rule); + + $this->assertTrue(isset($this->client()->analytics->rules()[$this->ruleName])); + + $rule = $this->client()->analytics->rules()[$this->ruleName]; + $this->assertInstanceOf('Typesense\AnalyticsRule', $rule); } -} +} \ No newline at end of file diff --git a/tests/Feature/AnalyticsRulesV1Test.php b/tests/Feature/AnalyticsRulesV1Test.php new file mode 100644 index 00000000..2f55468b --- /dev/null +++ b/tests/Feature/AnalyticsRulesV1Test.php @@ -0,0 +1,78 @@ + "popular_queries", + "params" => [ + "source" => [ + "collections" => ["products"] + ], + "destination" => [ + "collection" => "product_queries" + ], + "expand_query" => false, + "limit" => 1000 + ] + ]; + private $ruleUpsertResponse = null; + + protected function setUp(): void + { + parent::setUp(); + + if ($this->isV30OrAbove()) { + $this->markTestSkipped('Analytics is deprecated in Typesense v30+'); + } + + $this->ruleUpsertResponse = $this->client()->analyticsV1->rules()->upsert($this->ruleName, $this->ruleConfiguration); + } + + protected function tearDown(): void + { + if (!$this->isV30OrAbove()) { + try { + $rules = $this->client()->analyticsV1->rules()->retrieve(); + if (is_array($rules) && isset($rules['rules'])) { + foreach ($rules['rules'] as $rule) { + $this->client()->analyticsV1->rules()->{$rule['name']}->delete(); + } + } + } catch (Exception $e) { + } + } + } + + public function testCanUpsertARule(): void + { + $this->assertEquals($this->ruleName, $this->ruleUpsertResponse['name']); + } + + public function testCanRetrieveARule(): void + { + $returnData = $this->client()->analyticsV1->rules()[$this->ruleName]->retrieve(); + $this->assertEquals($returnData['name'], $this->ruleName); + } + + public function testCanDeleteARule(): void + { + $returnData = $this->client()->analyticsV1->rules()[$this->ruleName]->delete(); + $this->assertEquals($returnData['name'], $this->ruleName); + + $this->expectException(ObjectNotFound::class); + $this->client()->analyticsV1->rules()[$this->ruleName]->retrieve(); + } + + public function testCanRetrieveAllRules(): void + { + $returnData = $this->client()->analyticsV1->rules()->retrieve(); + $this->assertCount(1, $returnData['rules']); + } +} diff --git a/tests/Feature/SynonymsTest.php b/tests/Feature/SynonymsTest.php index 6cd5db05..5a61b871 100644 --- a/tests/Feature/SynonymsTest.php +++ b/tests/Feature/SynonymsTest.php @@ -17,6 +17,11 @@ class SynonymsTest extends TestCase protected function setUp(): void { parent::setUp(); + + if ($this->isV30OrAbove()) { + $this->markTestSkipped('Synonyms is deprecated in Typesense v30+, use SynonymSets instead'); + } + $this->setUpCollection('books'); $this->synonyms = $this->client()->collections['books']->synonyms; diff --git a/tests/TestCase.php b/tests/TestCase.php index 6a26447b..b9852b11 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -6,6 +6,7 @@ use Typesense\Client; use Mockery; use Typesense\ApiCall; +use Exception; abstract class TestCase extends BaseTestCase { @@ -98,4 +99,25 @@ protected function tearDownTypesense(): void $this->typesenseClient->collections[$collection['name']]->delete(); } } + + protected function isV30OrAbove(): bool + { + try { + $debug = $this->typesenseClient->debug->retrieve(); + $version = $debug['version']; + + if ($version === 'nightly') { + return true; + } + + if (preg_match('/^v(\d+)/', $version, $matches)) { + $majorVersion = (int) $matches[1]; + return $majorVersion >= 30; + } + + return false; + } catch (Exception $e) { + return false; + } + } }