Skip to content

Add dynamic search rules#910

Merged
Strift merged 12 commits into
mainfrom
feat/add-dynamic-search-rules
Apr 28, 2026
Merged

Add dynamic search rules#910
Strift merged 12 commits into
mainfrom
feat/add-dynamic-search-rules

Conversation

@Strift
Copy link
Copy Markdown
Collaborator

@Strift Strift commented Apr 28, 2026

Pull Request

Related issue

Fixes #904

What does this PR do?

  • Bump docker-compose.yml meilisearch version to v1.42
  • Add methods to interact with the dynamic search rules API: get, createOrUpdate, list, and delete
  • Add relevant code samples
  • Added AGENTS.md

AI disclosure

Cursor with gpt-5.5-medium, and gpt-5.3-codex-medium.

PR checklist

Please check if your PR fulfills the following requirements:

  • Did you use any AI tool while implementing this PR (code, tests, docs, etc.)? If yes, disclose it in the PR description and describe what it was used for. AI usage is allowed when it is disclosed.
  • Does this PR fix an existing issue, or have you listed the changes applied in the PR description (and why they are needed)?
  • Have you read the contributing guidelines?
  • Have you made sure that the title is accurate and descriptive of the changes?

Thank you so much for contributing to Meilisearch!

Summary by CodeRabbit

  • New Features

    • Dynamic search rules: list, fetch, update (patch) and delete with filtering, pagination, and client access.
  • Documentation

    • Added workflow guidance, endpoint/contract typing guidance, Docker Compose commands, and PHP code samples for dynamic search rules and lint/test commands.
  • Tests

    • Added unit and endpoint tests for contracts, queries, results, updates, and lifecycle behaviors.
  • Chores

    • Updated Meilisearch service image to v1.42.0.

@Strift Strift requested a review from norkunas April 28, 2026 04:45
@Strift Strift added the enhancement New feature or request label Apr 28, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 28, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds first-class support for Meilisearch Dynamic Search Rules: new contract types, a DynamicSearchRules endpoint with CRUD methods, a delegate trait wired into the Client, tests and code samples, docs, and a Meilisearch image bump in docker-compose.yml.

Changes

Cohort / File(s) Summary
Documentation & Config
AGENTS.md, src/Contracts/AGENTS.md, src/Endpoints/AGENTS.md, .code-samples.meilisearch.yaml, docker-compose.yml
Adds workflow and typing guidance, dynamic-search-rules code samples, and updates Meilisearch image tag to getmeili/meilisearch-enterprise:v1.42.0.
Client Integration
src/Client.php
Wires HandlesDynamicSearchRules trait into the client and constructs a DynamicSearchRules endpoint instance during initialization.
Endpoint & Delegate
src/Endpoints/DynamicSearchRules.php, src/Endpoints/Delegates/HandlesDynamicSearchRules.php
Adds DynamicSearchRules endpoint implementing POST (list), GET (fetch), PATCH (create/update), DELETE (remove) and a delegate trait exposing these methods on the client.
Contracts
src/Contracts/DynamicSearchRule.php, src/Contracts/DynamicSearchRulesFilter.php, src/Contracts/DynamicSearchRulesQuery.php, src/Contracts/DynamicSearchRulesResults.php, src/Contracts/UpdateDynamicSearchRuleQuery.php
Introduces five contract classes: rule model, filter, query builder, paginated results wrapper, and update-payload builder with fluent setters and precise toArray() serialization.
Tests
tests/Contracts/DynamicSearchRuleTest.php, tests/Contracts/DynamicSearchRulesQueryTest.php, tests/Contracts/DynamicSearchRulesResultsTest.php, tests/Contracts/UpdateDynamicSearchRuleQueryTest.php, tests/Endpoints/DynamicSearchRulesTest.php
Adds unit tests for contracts and integration tests exercising list/create/update/get/delete flows with setup/teardown enabling the experimental feature.

Sequence Diagram(s)

sequenceDiagram
    participant User as "User"
    participant Client as "Client"
    participant Delegate as "HandlesDynamicSearchRules"
    participant Endpoint as "DynamicSearchRules"
    participant API as "Meilisearch API"

    User->>Client: getDynamicSearchRules(options)
    Client->>Delegate: delegate call
    Delegate->>Endpoint: all(options)
    Endpoint->>Endpoint: options?.toArray()
    Endpoint->>API: POST /dynamic-search-rules
    API-->>Endpoint: { results, offset, limit, total }
    Endpoint->>Endpoint: map results -> DynamicSearchRule::fromArray()
    Endpoint-->>Delegate: DynamicSearchRulesResults
    Delegate-->>Client: DynamicSearchRulesResults
    Client-->>User: DynamicSearchRulesResults

    User->>Client: updateDynamicSearchRule(request)
    Client->>Delegate: delegate call
    Delegate->>Endpoint: update(request)
    Endpoint->>Endpoint: request.toArray()
    Endpoint->>API: PATCH /dynamic-search-rules/{uid}
    API-->>Endpoint: raw rule
    Endpoint->>Endpoint: DynamicSearchRule::fromArray()
    Endpoint-->>Delegate: DynamicSearchRule
    Delegate-->>Client: DynamicSearchRule
    Client-->>User: DynamicSearchRule
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~28 minutes

Poem

🐇 I hopped through structs and tests anew,

I pinned a doc and chased a queue.
Rules now dance where queries play,
I left a carrot in the tray. 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 57.41% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Add dynamic search rules' clearly and concisely summarizes the main objective of the changeset.
Linked Issues check ✅ Passed All code requirements from issue #904 are met: SDK endpoints for list, get, patch, and delete dynamic search rules are implemented [DynamicSearchRules, HandlesDynamicSearchRules], comprehensive test coverage is provided [DynamicSearchRulesTest], and code samples are added to .code-samples.meilisearch.yaml.
Out of Scope Changes check ✅ Passed All changes are scoped to dynamic search rules implementation: contract classes, endpoint handlers, delegate trait, tests, documentation, and code samples. The Meilisearch version bump to v1.42.0 is necessary for API compatibility.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/add-dynamic-search-rules

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
tests/Contracts/DynamicSearchRulesQueryTest.php (1)

32-47: Consider adding one regression test for active=false.

This would harden behavior around boolean serialization and protect against accidental false-value filtering.

Suggested test case
 final class DynamicSearchRulesQueryTest extends TestCase
 {
+    public function testSetFilterWithInactiveRule(): void
+    {
+        $data = (new DynamicSearchRulesQuery())
+            ->setFilter(
+                (new DynamicSearchRulesFilter())
+                    ->setAttributePatterns(['movie-rule'])
+                    ->setActive(false)
+            );
+
+        self::assertSame([
+            'filter' => [
+                'attributePatterns' => ['movie-rule'],
+                'active' => false,
+            ],
+        ], $data->toArray());
+    }
+
     public function testSetFilter(): void
     {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/Contracts/DynamicSearchRulesQueryTest.php` around lines 32 - 47, Add a
regression test that verifies boolean false is serialized correctly: create a
new test method (e.g., testSetFilterInactive) in DynamicSearchRulesQueryTest
which builds a DynamicSearchRulesQuery with
DynamicSearchRulesFilter()->setAttributePatterns([...])->setActive(false) and
assert that ->toArray() returns
['filter'=>['attributePatterns'=>[...],'active'=>false]] to ensure false values
are not omitted or converted.
src/Contracts/DynamicSearchRulesResults.php (1)

25-30: Reduce duplicated payload shape docs with a PHPStan alias.

The constructor and toArray() repeat the same shape. Defining a single alias improves maintainability and avoids drift.

Proposed refactor
 final class DynamicSearchRulesResults extends Data
 {
+    /**
+     * `@phpstan-type` DynamicSearchRulesResultsPayload array{
+     *     results: array<int, DynamicSearchRule>,
+     *     offset: non-negative-int,
+     *     limit: non-negative-int,
+     *     total: non-negative-int
+     * }
+     */
+
     /**
-     * `@param` array{
-     *     results: array<int, DynamicSearchRule>,
-     *     offset: non-negative-int,
-     *     limit: non-negative-int,
-     *     total: non-negative-int
-     * } $params
+     * `@param` DynamicSearchRulesResultsPayload $params
      */
     public function __construct(array $params)
     {
         parent::__construct($params['results']);
@@
     /**
-     * `@return` array{
-     *     results: array<int, DynamicSearchRule>,
-     *     offset: non-negative-int,
-     *     limit: non-negative-int,
-     *     total: non-negative-int
-     * }
+     * `@return` DynamicSearchRulesResultsPayload
      */
     public function toArray(): array
As per coding guidelines, "Import shared aliases with `@phpstan-import-type` instead of duplicating shapes."

Also applies to: 74-79

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/Contracts/DynamicSearchRulesResults.php` around lines 25 - 30, Define a
single PHPStan array-shape alias for the payload and import it instead of
duplicating the shape in this file; add an alias (e.g., `@phpstan-type`
DynamicSearchRulesResultsShape array{results: array<int, DynamicSearchRule>,
offset: non-negative-int, limit: non-negative-int, total: non-negative-int}) in
a central contract (or at top of this file) and then replace the duplicated
shape docs used on DynamicSearchRulesResults::__construct and
DynamicSearchRulesResults::toArray with an import line like `@phpstan-import-type`
DynamicSearchRulesResultsShape from <wherever you placed it> and reference that
alias in the `@param/`@return tags so both the constructor and toArray use the
single shared alias.
src/Endpoints/DynamicSearchRules.php (1)

40-60: Optional DRY cleanup for repeated rule-path construction.

self::PATH.'/'.$uid is repeated in three methods. A small helper would reduce duplication and future drift.

♻️ Proposed refactor
 class DynamicSearchRules extends Endpoint
 {
     protected const PATH = '/dynamic-search-rules';
+
+    /**
+     * `@param` non-empty-string $uid
+     */
+    private function rulePath(string $uid): string
+    {
+        return self::PATH.'/'.$uid;
+    }

     /**
      * `@param` non-empty-string $uid
      */
     public function get(string $uid): DynamicSearchRule
     {
-        $response = $this->http->get(self::PATH.'/'.$uid);
+        $response = $this->http->get($this->rulePath($uid));

         return DynamicSearchRule::fromArray($response);
     }

     public function update(UpdateDynamicSearchRuleQuery $request): DynamicSearchRule
     {
-        $response = $this->http->patch(self::PATH.'/'.$request->uid, $request->toArray());
+        $response = $this->http->patch($this->rulePath($request->uid), $request->toArray());

         return DynamicSearchRule::fromArray($response);
     }

     /**
      * `@param` non-empty-string $uid
      */
     public function delete(string $uid): ?array
     {
-        return $this->http->delete(self::PATH.'/'.$uid);
+        return $this->http->delete($this->rulePath($uid));
     }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/Endpoints/DynamicSearchRules.php` around lines 40 - 60, The three methods
get, update, and delete repeat building the endpoint string using
self::PATH.'/'. $uid; add a small private helper method (e.g., pathFor(string
$uid) or buildPath(string $uid)) that returns self::PATH.'/'.$uid, and update
DynamicSearchRules::get, DynamicSearchRules::update (which uses $request->uid),
and DynamicSearchRules::delete to call that helper to remove duplication and
centralize path construction.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/Contracts/DynamicSearchRulesQuery.php`:
- Around line 55-63: The phpdoc for DynamicSearchRulesQuery currently
re-declares the nested filter array shape; instead import the shared alias with
`@phpstan-import-type` DynamicSearchRulesFilter from the DynamicSearchRulesFilter
contract and then reference that alias in the return phpdoc for toArray() (use
the imported type for the filter key instead of inlining
attributePatterns/active). Add the `@phpstan-import-type` statement near the top
of the file and update the return array shape to use the imported alias so the
filter shape is a single source of truth.

---

Nitpick comments:
In `@src/Contracts/DynamicSearchRulesResults.php`:
- Around line 25-30: Define a single PHPStan array-shape alias for the payload
and import it instead of duplicating the shape in this file; add an alias (e.g.,
`@phpstan-type` DynamicSearchRulesResultsShape array{results: array<int,
DynamicSearchRule>, offset: non-negative-int, limit: non-negative-int, total:
non-negative-int}) in a central contract (or at top of this file) and then
replace the duplicated shape docs used on DynamicSearchRulesResults::__construct
and DynamicSearchRulesResults::toArray with an import line like
`@phpstan-import-type` DynamicSearchRulesResultsShape from <wherever you placed
it> and reference that alias in the `@param/`@return tags so both the constructor
and toArray use the single shared alias.

In `@src/Endpoints/DynamicSearchRules.php`:
- Around line 40-60: The three methods get, update, and delete repeat building
the endpoint string using self::PATH.'/'. $uid; add a small private helper
method (e.g., pathFor(string $uid) or buildPath(string $uid)) that returns
self::PATH.'/'.$uid, and update DynamicSearchRules::get,
DynamicSearchRules::update (which uses $request->uid), and
DynamicSearchRules::delete to call that helper to remove duplication and
centralize path construction.

In `@tests/Contracts/DynamicSearchRulesQueryTest.php`:
- Around line 32-47: Add a regression test that verifies boolean false is
serialized correctly: create a new test method (e.g., testSetFilterInactive) in
DynamicSearchRulesQueryTest which builds a DynamicSearchRulesQuery with
DynamicSearchRulesFilter()->setAttributePatterns([...])->setActive(false) and
assert that ->toArray() returns
['filter'=>['attributePatterns'=>[...],'active'=>false]] to ensure false values
are not omitted or converted.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 3527ad2c-6de1-466c-8eba-d3352b2773ba

📥 Commits

Reviewing files that changed from the base of the PR and between ee1654d and fbc7d51.

📒 Files selected for processing (17)
  • AGENTS.md
  • docker-compose.yml
  • src/Client.php
  • src/Contracts/AGENTS.md
  • src/Contracts/DynamicSearchRule.php
  • src/Contracts/DynamicSearchRulesFilter.php
  • src/Contracts/DynamicSearchRulesQuery.php
  • src/Contracts/DynamicSearchRulesResults.php
  • src/Contracts/UpdateDynamicSearchRuleQuery.php
  • src/Endpoints/AGENTS.md
  • src/Endpoints/Delegates/HandlesDynamicSearchRules.php
  • src/Endpoints/DynamicSearchRules.php
  • tests/Contracts/DynamicSearchRuleTest.php
  • tests/Contracts/DynamicSearchRulesQueryTest.php
  • tests/Contracts/DynamicSearchRulesResultsTest.php
  • tests/Contracts/UpdateDynamicSearchRuleQueryTest.php
  • tests/Endpoints/DynamicSearchRulesTest.php

Comment thread src/Contracts/DynamicSearchRulesQuery.php
Comment thread src/Contracts/DynamicSearchRulesQuery.php Outdated
Comment thread src/Contracts/DynamicSearchRulesResults.php Outdated
Comment thread src/Endpoints/DynamicSearchRules.php Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/Contracts/DynamicSearchRulesFilter.php`:
- Around line 39-44: Add a reusable PHPStan type alias for the filter payload
inside the DynamicSearchRulesFilter contract (e.g., declare /** `@phpstan-type`
DynamicSearchRulesFilterPayload array{attributePatterns?:
list<non-empty-string>, active?: bool} */ above the class) and then replace the
duplicated anonymous shape in DynamicSearchRulesQuery by importing that alias
with /** `@phpstan-import-type` DynamicSearchRulesFilterPayload from
DynamicSearchRulesFilter */; update the toArray() docblock in
DynamicSearchRulesFilter to reference the named alias and remove the duplicated
shape from DynamicSearchRulesQuery so both files use
DynamicSearchRulesFilterPayload.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 50a3e36e-79eb-4096-95f1-1c4449e9c869

📥 Commits

Reviewing files that changed from the base of the PR and between 88c28cc and f199c20.

📒 Files selected for processing (3)
  • src/Contracts/DynamicSearchRulesFilter.php
  • src/Contracts/DynamicSearchRulesQuery.php
  • src/Endpoints/DynamicSearchRules.php
✅ Files skipped from review due to trivial changes (1)
  • src/Contracts/DynamicSearchRulesQuery.php
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/Endpoints/DynamicSearchRules.php

Comment thread src/Contracts/DynamicSearchRulesFilter.php
@Strift Strift requested a review from norkunas April 28, 2026 05:31
Comment thread src/Contracts/DynamicSearchRulesResults.php Outdated
Comment thread src/Contracts/DynamicSearchRulesResults.php Outdated
Co-authored-by: Tomas Norkūnas <norkunas.tom@gmail.com>
@Strift Strift enabled auto-merge April 28, 2026 06:04
@Strift Strift added this pull request to the merge queue Apr 28, 2026
Merged via the queue into main with commit 6ce13f2 Apr 28, 2026
10 checks passed
@Strift Strift deleted the feat/add-dynamic-search-rules branch April 28, 2026 06:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Meilisearch v1.41] Add support for Dynamic Search Rules

2 participants