Skip to content

feat: add Dynamic Search Rules endpoints (#495) - #497

Open
ibrahim-iqbal wants to merge 2 commits into
meilisearch:mainfrom
ibrahim-iqbal:feature/495-dynamic-search-rules
Open

feat: add Dynamic Search Rules endpoints (#495)#497
ibrahim-iqbal wants to merge 2 commits into
meilisearch:mainfrom
ibrahim-iqbal:feature/495-dynamic-search-rules

Conversation

@ibrahim-iqbal

@ibrahim-iqbal ibrahim-iqbal commented Jul 26, 2026

Copy link
Copy Markdown

Fixes #495.

Summary

Adds SDK support for the experimental Dynamic Search Rules API introduced in Meilisearch v1.50.0. The endpoints require the dynamicSearchRules experimental feature flag to be enabled on the server:

await client.http.updateExperimentalFeatures(
  const UpdateExperimentalFeatures(dynamicSearchRules: true),
);

New client methods on MeiliSearchClient

Endpoint Method Returns
POST /dynamic-search-rules listDynamicSearchRules({params}) Result<DynamicSearchRule>
GET /dynamic-search-rules/{uid} getDynamicSearchRule(uid) DynamicSearchRule
PATCH /dynamic-search-rules/{uid} updateOrCreateDynamicSearchRule(uid, rule) Task (async)
DELETE /dynamic-search-rules/{uid} deleteDynamicSearchRule(uid) Task (async)

All four are annotated with @RequiredMeiliServerVersion('1.50.0').

Design notes

  • DynamicSearchRule.conditions and .actions are exposed as raw Map<String, Object?> / List<Map<String, Object?>> rather than fully typed sub-models. The rule schema is young and still evolving on the server side; keeping these fields raw means the SDK keeps working when the server adds sub-fields without a coordinated SDK release. Consumers that want strongly typed access can wrap them at their layer.
  • DynamicSearchRule.toUpsertBody() is sparse (nulls omitted) so the PATCH endpoint acts as a true partial upsert.
  • DynamicSearchRulesQuery.toBody() mirrors the same sparse-body pattern for the POST list endpoint.

Tests

9 unit tests in test/dynamic_search_rules_serialization_test.dart:

  • Full-response parsing (all documented fields incl. nested conditions and actions)
  • Sparse-response tolerance (only uid present)
  • Unparseable timestamp handled without throwing
  • toUpsertBody sparse behavior + verbatim conditions/actions
  • DynamicSearchRulesQuery.toBody empty / full / sparse round-trip

Integration tests against a live Meilisearch are intentionally not added: the endpoints are experimental and require a server-side feature flag toggle that isn't in the current test-suite setup. Happy to add them in a follow-up once the flag is wired into the CI setup, or as part of this PR if there's guidance on the preferred approach.

Code samples

Added the four keys the documentation site expects to .code-samples.meilisearch.yaml:

  • list_dynamic_search_rules_1
  • get_dynamic_search_rule_1
  • patch_dynamic_search_rule_1
  • delete_dynamic_search_rule_1

Sample bodies mirror the equivalent curl samples in meilisearch/documentation.

Verification

  • dart test test/dynamic_search_rules_serialization_test.dart — 9/9 pass
  • dart analyze — clean on all touched files

Summary by CodeRabbit

  • New Features

    • Added experimental Dynamic Search Rules support for Meilisearch v1.50.0+.
    • List, view, create or update, and delete dynamic search rules.
    • Added support for pagination and filtering when listing rules.
    • Added rule data models with conditions, actions, priorities, descriptions, status, and timestamps.
    • Included Dart client code samples demonstrating common Dynamic Search Rules workflows.
  • Tests

    • Added coverage for rule serialization, deserialization, sparse updates, and query parameters.

Add SDK support for the experimental Dynamic Search Rules API introduced
in Meilisearch v1.50.0. The endpoints require the `dynamicSearchRules`
experimental feature flag to be enabled on the server.

New client methods on `MeiliSearchClient`:
- `listDynamicSearchRules({params})`   -> Result<DynamicSearchRule>
- `getDynamicSearchRule(uid)`          -> DynamicSearchRule
- `updateOrCreateDynamicSearchRule(uid, rule)` -> Task (async)
- `deleteDynamicSearchRule(uid)`       -> Task (async)

Design notes:
- `DynamicSearchRule.conditions` and `.actions` are exposed as raw
  maps/lists so the SDK keeps working when the server adds sub-fields
  without a coordinated SDK release. Consumers wanting strongly typed
  access can wrap them at their layer.
- `toUpsertBody()` is sparse (nulls omitted) so PATCH acts as a real
  partial upsert.
- `DynamicSearchRulesQuery` mirrors the same sparse-body pattern for
  `POST /dynamic-search-rules`.

Tests: 9 serialization / query-body unit tests covering full-response
parsing, sparse responses, unparseable timestamps, and body-shape
round-tripping. Integration tests are intentionally not added: the
endpoints are experimental and require a server-side feature flag toggle
that isn't in the current test setup.

Code samples `list_dynamic_search_rules_1`, `get_dynamic_search_rule_1`,
`patch_dynamic_search_rule_1`, `delete_dynamic_search_rule_1` added to
`.code-samples.meilisearch.yaml` matching the keys used by the
Meilisearch documentation site.
@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@ibrahim-iqbal, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 26 seconds

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 2ef5ad74-e364-445a-b95c-f32df1cd1280

📥 Commits

Reviewing files that changed from the base of the PR and between 6ddc1e2 and abff894.

📒 Files selected for processing (4)
  • .code-samples.meilisearch.yaml
  • lib/src/query_parameters/dynamic_search_rules_query.dart
  • lib/src/results/dynamic_search_rule.dart
  • test/dynamic_search_rules_serialization_test.dart
📝 Walkthrough

Walkthrough

Adds experimental Dynamic Search Rules support to the Dart client, including public models, query serialization, four API endpoints, async task handling, serialization tests, and usage examples.

Changes

Dynamic Search Rules

Layer / File(s) Summary
Rule and query contracts
lib/src/results/dynamic_search_rule.dart, lib/src/query_parameters/dynamic_search_rules_query.dart, lib/src/results/_exports.dart, lib/src/query_parameters/_exports.dart, test/dynamic_search_rules_serialization_test.dart
Adds rule parsing, sparse upsert serialization, query-body serialization, public exports, and coverage for full, sparse, invalid-timestamp, and null-field inputs.
Client endpoint integration
lib/src/client.dart
Adds version-gated methods for listing, retrieving, upserting, and deleting rules through the Dynamic Search Rules API.
Usage examples
.code-samples.meilisearch.yaml
Adds Dart examples for all four Dynamic Search Rules operations.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant DartClient
  participant MeilisearchAPI
  participant TaskQueue
  DartClient->>MeilisearchAPI: List or retrieve a dynamic rule
  MeilisearchAPI-->>DartClient: DynamicSearchRule response
  DartClient->>MeilisearchAPI: Upsert or delete a dynamic rule
  MeilisearchAPI->>TaskQueue: Create asynchronous task
  TaskQueue-->>DartClient: Task response
Loading

Possibly related issues

  • meilisearch/meilisearch-ruby#708 — Covers the same Dynamic Search Rules endpoints, models, tests, and examples.
  • meilisearch/meilisearch-swift#528 — Covers equivalent Dynamic Search Rules SDK functionality.
  • meilisearch/meilisearch-php#932 — Concerns the same v1.50 Dynamic Search Rules API and schema support.

Poem

A bunny hops through rules so bright,
Pins a search result just right.
PATCH makes tasks, DELETE too,
Queries skip the nulls they knew.
Four new paths now dance in flight!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately describes the main change: adding Dynamic Search Rules endpoints.
Linked Issues check ✅ Passed The PR covers all four endpoints, async task handling, tests, and the required documentation samples.
Out of Scope Changes check ✅ Passed No unrelated changes are indicated; the edits stay focused on Dynamic Search Rules support and its tests/docs.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@lib/src/query_parameters/dynamic_search_rules_query.dart`:
- Around line 13-15: The DynamicSearchRulesQuery filter must be a structured
nullable raw map rather than a string expression. Update the filter field and
its serialization in dynamic_search_rules_query.dart to preserve and emit the
map unchanged when present, and update
test/dynamic_search_rules_serialization_test.dart to use a valid structured
filter fixture such as query/active or attributePatterns/active.

In `@lib/src/results/dynamic_search_rule.dart`:
- Line 18: Rename DynamicSearchRule.priority to precedence throughout the model,
clarify its documentation to state that lower values are processed first, and
update fromJson and toUpsertBody to read and serialize the precedence field
instead of priority.
🪄 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 Plus

Run ID: c88e66a1-5252-43fe-a4fe-8372c1a742b6

📥 Commits

Reviewing files that changed from the base of the PR and between 6f3bee9 and 6ddc1e2.

📒 Files selected for processing (7)
  • .code-samples.meilisearch.yaml
  • lib/src/client.dart
  • lib/src/query_parameters/_exports.dart
  • lib/src/query_parameters/dynamic_search_rules_query.dart
  • lib/src/results/_exports.dart
  • lib/src/results/dynamic_search_rule.dart
  • test/dynamic_search_rules_serialization_test.dart

Comment thread lib/src/query_parameters/dynamic_search_rules_query.dart Outdated
Comment thread lib/src/results/dynamic_search_rule.dart Outdated
Two review findings from CodeRabbit on meilisearch#497:

1. Rename `priority` to `precedence` on DynamicSearchRule.
   Meilisearch v1.50.0 renamed the ordering field and rejects the old
   `priority` key on the wire. Lower numeric `precedence` values are
   applied first (rule with precedence: 1 wins over precedence: 5).
   Updates the field name, KDoc, fromJson lookup, and toUpsertBody
   emission accordingly.

2. Change `DynamicSearchRulesQuery.filter` from a bare filter-string
   to a structured DynamicSearchRulesFilter object. In v1.50.0 the
   list endpoint filter is an object with `query` (free-text search
   across description + conditions.query.words) and `active` (bool
   status filter), not a filter-expression string. toBody() drops
   an entirely empty filter object so unconfigured queries don't send
   {} on the wire.

Tests updated: precedence round-trip, structured filter round-trip,
empty-filter drop, sparse-filter emission. `.code-samples.meilisearch.yaml`
patch sample uses `precedence`.
@ibrahim-iqbal

Copy link
Copy Markdown
Author

Thanks @coderabbitai — both findings addressed in abff894:

1. priorityprecedence (dynamic_search_rule.dart)
Renamed the field, updated KDoc to note lower values win, moved the JSON lookup + upsert emission over. Verified server-side: v1.50.0 rejects priority.

2. filter string → structured object (dynamic_search_rules_query.dart)
Introduced DynamicSearchRulesFilter carrying the actual documented fields — query (free-text over description + conditions.query.words) and active (status filter). toBody() drops an entirely empty filter so unconfigured queries don't send {} on the wire.

Tests + .code-samples.meilisearch.yaml updated. 10/10 pass, dart analyze clean.

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

@ibrahim-iqbal Thanks for the thorough update. The precedence correction and structured, omission-aware filter serialization address both findings.

🐇✨


✏️ Learnings added
Learnt from: ibrahim-iqbal
URL: https://github.com/meilisearch/meilisearch-dart/pull/497

Timestamp: 2026-07-26T12:38:49.494Z
Learning: For the Dart SDK Dynamic Search Rules API (`lib/src/results/dynamic_search_rule.dart`), the server field is `precedence`, not `priority`; lower precedence values win, and Meilisearch v1.50.0 rejects `priority`.

Learnt from: ibrahim-iqbal
URL: https://github.com/meilisearch/meilisearch-dart/pull/497

Timestamp: 2026-07-26T12:38:49.494Z
Learning: For Dynamic Search Rules listing in the Dart SDK (`lib/src/query_parameters/dynamic_search_rules_query.dart`), use `DynamicSearchRulesFilter` with optional `query` (searches descriptions and `conditions.query.words`) and `active` fields. `DynamicSearchRulesQuery.toBody()` must omit a filter whose fields are all null rather than send an empty JSON object.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


If you found this review helpful, would you consider giving us a shout-out on X?

Thank you for using CodeRabbit!

@ibrahim-iqbal

Copy link
Copy Markdown
Author

I've pushed fixes for both of CodeRabbit's points (the filter body now uses query, and priority is renamed to precedence with lower values winning) and the bot has confirmed them, so the threads should be settled now.

@curquiza when you get a chance, could this get a review? Happy to make any changes needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Meilisearch v1.50.0] Add Dynamic Search Rules (experimental)

1 participant