Support LIKE and NOT LIKE operators in database backend

Created on 19 January 2024, 11 months ago

Problem/Motivation

I want to use a String like filter in views when using the database backend.

By default, search_api uses the search_api_string plugin for all views fields, however there's nothing stopping a custom module overiding that to use core's string plugin to get containers, starts with, etc operators.

However, you're hard locked out of these by BackendPluginBase::validateOperator because it does not support LIKE and NOT LIKE. Manually hacking these in makes the filter work as expected.

The Database backend could support these without necessarily exposing them via views data (i.e allowing custom modules to use string filters if needed).

Steps to reproduce

Proposed resolution

Override validateOperator in the Database backend and allow LIKE and NOT LIKE.

Remaining tasks

Feature request
Status

Active

Version

1.0

Component

General code

Created by

🇦🇺Australia acbramley

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

  • Issue created by @acbramley
  • Merge request !104Support LIKE and NOT LIKE in DB backend. → (Open) created by acbramley
  • Open in Jenkins → Open on Drupal.org →
    Core: 10.1.4 + Environment: PHP 8.2 & sqlite-3.34
    last update 11 months ago
    Composer require-dev failure
  • Status changed to Needs review 11 months ago
  • 🇦🇺Australia acbramley

    NR for getting an idea if this could be supported.

  • Open in Jenkins → Open on Drupal.org →
    Core: 10.1.4 + Environment: PHP 8.2 & sqlite-3.34
    last update 11 months ago
    545 pass
  • 🇦🇹Austria drunken monkey Vienna, Austria

    Thanks for the suggestion!
    Sure, if using those operators already works correctly when using custom code to override the filter plugins then it makes sense not to prevent this use case in the backend plugin’s code. Seems a very simple change for the moment.
    See also Implement like operator for search_api_db Active , which discusses a more elaborate implementation that also offers the new operators in the UI.
    However, this would still need some test coverage before it can be committed. Ideally, we’d already test this in combination with Views, when using Core’s built-in string plugin as you describe. But just making sure it can be used internally would already be fine, too, I think.

    Also, as you already found out, testing issue forks still doesn’t work with this module, so please still use patches for now. Now that there’s finally been movement in the test bot issue queue we’ll hopefully have this resolved soon.
    Attaching a patch with some small code style changes.

  • Status changed to Needs work 10 months ago
  • 🇦🇹Austria drunken monkey Vienna, Austria

    NW for the tests.

  • I have tried this patch but I have got one question, how do I alter the operator for the Fulltext search ?
    Tried something like this:

      function mymodule_search_api_query_alter(\Drupal\search_api\Query\QueryInterface &$query) {
        foreach ($conditionGroups as &$conditionGroup) {
          foreach ($conditionGroup->getConditions() as &$condition) { 
            // no condition found for the fulltext filter.
          }
      }
    }
    

    but the condition for the Fulltext search filter is not there, did I miss something or is it something unusual ?

  • 🇦🇹Austria drunken monkey Vienna, Austria

    The fulltext search is actually not a “condition” in the Search API, but a separate part of the search query, the “keys”.
    You can retrieve them via $query->getKeys() – they’ll usually be represented as an array structure, see the doc block of \Drupal\search_api\ParseMode\ParseModeInterface::parseInput() for details.

    Fulltext search basically just has two operators, AND (“contains all of these words”) and OR (“contains any of these words”). To switch to OR, you can either do

        $query->getParseMode()->setConjunction('OR');
    

    before the keywords are set on the query or

        $keys = &$query->getKeys();
        if (is_array($keys)) {
          $keys['#conjunction'] = 'OR';
        }
    

    afterwards.

    If $keys is a string, not an array, than the way to express an OR conjunction depends on the backend. (For the database backend, there is no way to do that with unparsed keywords, i.e., if $keys is a string. Use the “Terms” parse mode instead.)

Production build 0.71.5 2024