Skip to content

Add dynamic search rules support - #710

Open
aouxwoux wants to merge 1 commit into
meilisearch:mainfrom
aouxwoux:codex/dynamic-search-rules
Open

aouxwoux wants to merge 1 commit into
meilisearch:mainfrom
aouxwoux:codex/dynamic-search-rules

Conversation

@aouxwoux

@aouxwoux aouxwoux commented Aug 8, 2026 •

Copy link
Copy Markdown

Why?

adds ruby client support for the dynamic search rules API introduced in meilisearch v1.50, including the filter condition and lastUpdatedAt response added in v1.51.

closes #708
closes #709

What?

  • adds list, get, upsert, and delete methods on Meilisearch::Client
  • returns Models::Task for the asynchronous upsert and delete routes
  • converts nested rule attributes while preserving user-defined filter facet names
  • adds integration coverage for pagination, filtering, retrieval, creation, updates, deletion, and v1.51 response fields
  • adds the four documentation code samples requested by [Meilisearch v1.50.0] Add Dynamic Search Rules (experimental) #708

Testing

  • 4 focused dynamic search rule examples pass against meilisearch enterprise v1.51.0
  • 462 examples pass in the broader suite on a fresh local database
  • all 61 ruby files pass rubocop
  • code sample yaml parses successfully

one unrelated compact integration example is excluded from the broader windows run because index compaction fails on the local windows server.

AI assistance

used codex to help implement the client methods and draft the integration tests. i reviewed the diff and validated it against meilisearch enterprise v1.51.0 locally.

See Also

Changelog

  • adds dynamic search rules support, including v1.51 filter conditions

Summary by CodeRabbit

  • New Features
    • Added Ruby SDK support for managing dynamic search rules.
    • List and retrieve rules with pagination and filtering options.
    • Create, update, and delete rules asynchronously.
    • Support complex rule conditions and pinning actions.
  • Documentation
    • Added Ruby usage examples for dynamic search rule operations.

@coderabbitai

coderabbitai Bot commented Aug 8, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The Ruby SDK adds methods for listing, retrieving, upserting, and deleting dynamic search rules. It normalizes nested rule conditions and actions, returns asynchronous tasks for mutations, adds RSpec coverage, and provides Ruby code samples.

Changes

Dynamic search rules

Layer / File(s) Summary
Client operations and request normalization
lib/meilisearch/client.rb
The client adds list, get, upsert, and delete methods. Private helpers normalize nested query, time, filter, selector, and action fields.
Rule lifecycle coverage
spec/meilisearch/client/dynamic_search_rules_spec.rb
Specs cover experimental-feature setup, pagination, filtering, retrieval, asynchronous upsert and deletion, and missing-rule errors.
Ruby usage examples
.code-samples.meilisearch.yaml
Examples cover listing, retrieving, patching, and deleting dynamic search rules.

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

Sequence Diagram(s)

sequenceDiagram
  participant RubyClient
  participant MeilisearchAPI
  participant ModelsTask
  RubyClient->>MeilisearchAPI: List or retrieve dynamic search rules
  RubyClient->>MeilisearchAPI: Upsert or delete a dynamic search rule
  MeilisearchAPI-->>RubyClient: Rule response or task response
  RubyClient->>ModelsTask: Wrap asynchronous response as Models::Task
Loading

Possibly related issues

  • meilisearch/meilisearch-swift#528: Covers equivalent Dynamic Search Rules SDK endpoints, tests, and code samples.
  • meilisearch/meilisearch-python#1267: Covers overlapping Dynamic Search Rules CRUD and nested condition support.

Poem

A rabbit found rules in a burrow so deep,
With pins for the products and tasks to keep.
List, fetch, patch, and delete with care,
Nested conditions now travel there.
“Hop!” said the rabbit, “The SDK is complete!”

🚥 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 clearly and concisely describes the primary change: adding dynamic search rules support.
Linked Issues check ✅ Passed The changes implement all four endpoints, async task handling, pagination and filtering, filter conditions, timestamps, tests, and documentation samples [#708] [#709].
Out of Scope Changes check ✅ Passed All changes support dynamic search rules implementation, coverage, or documentation required by the linked issues.
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: 1

🤖 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/meilisearch/client.rb`:
- Around line 523-536: Update dynamic_search_rule_body and
dynamic_search_rule_conditions so Utils.transform_attributes does not
recursively transform conditions.filter.values; preserve facet keys such as
product_type while continuing to transform only the structural condition fields.
Add an integration case covering an underscored facet name and verify the
generated server filter condition retains the original key.
🪄 Autofix

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: 192dd0c2-9256-4a69-83f2-830c66c407be

📥 Commits

Reviewing files that changed from the base of the PR and between 857afce and ec56acc.

📒 Files selected for processing (3)
  • .code-samples.meilisearch.yaml
  • lib/meilisearch/client.rb
  • spec/meilisearch/client/dynamic_search_rules_spec.rb

Comment thread lib/meilisearch/client.rb
Comment on lines +523 to +536
def dynamic_search_rule_body(options)
body = Utils.transform_attributes(options)
body['conditions'] = dynamic_search_rule_conditions(body['conditions']) if body['conditions']
body['actions'] = body['actions'].map { |entry| dynamic_search_rule_action(entry) } if body['actions']

body
end

def dynamic_search_rule_conditions(conditions)
conditions = Utils.transform_attributes(conditions)
['query', 'time', 'filter'].each do |condition|
conditions[condition] = Utils.transform_attributes(conditions[condition]) if conditions[condition]
end
conditions

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Preserve keys in filter.values.

Utils.transform_attributes recursively transforms nested hashes. At Line 524, it transforms conditions.filter.values before this helper can isolate it. A facet named product_type can become productType, which changes the server filter condition.

Keep filter.values unchanged. Transform only the structural condition fields. Add an integration case with an underscored facet name.

Proposed fix
 def dynamic_search_rule_body(options)
-  body = Utils.transform_attributes(options)
-  body['conditions'] = dynamic_search_rule_conditions(body['conditions']) if body['conditions']
+  body = options.dup
+  conditions = body.delete(:conditions) || body.delete('conditions')
+  body = Utils.transform_attributes(body)
+  body['conditions'] = dynamic_search_rule_conditions(conditions) if conditions
   body['actions'] = body['actions'].map { |entry| dynamic_search_rule_action(entry) } if body['actions']
 
   body
 end

 def dynamic_search_rule_conditions(conditions)
-  conditions = Utils.transform_attributes(conditions)
-  ['query', 'time', 'filter'].each do |condition|
-    conditions[condition] = Utils.transform_attributes(conditions[condition]) if conditions[condition]
+  conditions = conditions.dup
+  filter = conditions.delete(:filter) || conditions.delete('filter')
+  conditions = Utils.transform_attributes(conditions)
+
+  if filter
+    filter = filter.dup
+    values = filter.delete(:values) || filter.delete('values')
+    filter = Utils.transform_attributes(filter)
+    filter['values'] = values if values
+    conditions['filter'] = filter
   end
+
   conditions
 end
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def dynamic_search_rule_body(options)
body = Utils.transform_attributes(options)
body['conditions'] = dynamic_search_rule_conditions(body['conditions']) if body['conditions']
body['actions'] = body['actions'].map { |entry| dynamic_search_rule_action(entry) } if body['actions']
body
end
def dynamic_search_rule_conditions(conditions)
conditions = Utils.transform_attributes(conditions)
['query', 'time', 'filter'].each do |condition|
conditions[condition] = Utils.transform_attributes(conditions[condition]) if conditions[condition]
end
conditions
def dynamic_search_rule_body(options)
body = options.dup
conditions = body.delete(:conditions) || body.delete('conditions')
body = Utils.transform_attributes(body)
body['conditions'] = dynamic_search_rule_conditions(conditions) if conditions
body['actions'] = body['actions'].map { |entry| dynamic_search_rule_action(entry) } if body['actions']
body
end
def dynamic_search_rule_conditions(conditions)
conditions = conditions.dup
filter = conditions.delete(:filter) || conditions.delete('filter')
conditions = Utils.transform_attributes(conditions)
if filter
filter = filter.dup
values = filter.delete(:values) || filter.delete('values')
filter = Utils.transform_attributes(filter)
filter['values'] = values if values
conditions['filter'] = filter
end
conditions
🤖 Prompt for 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.

In `@lib/meilisearch/client.rb` around lines 523 - 536, Update
dynamic_search_rule_body and dynamic_search_rule_conditions so
Utils.transform_attributes does not recursively transform
conditions.filter.values; preserve facet keys such as product_type while
continuing to transform only the structural condition fields. Add an integration
case covering an underscored facet name and verify the generated server filter
condition retains the original key.

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.51.0] Add filter condition to Dynamic Search Rules [Meilisearch v1.50.0] Add Dynamic Search Rules (experimental)

1 participant