We should, internally, add some new operators in D8, which have been missed regularly in D7: IN, NOT IN, BETWEEN and NOT BETWEEN.
We should then of course also use and support them in the Views integration (could be a follow-up issue, though).

Estimated Value and Story Points

This issue was identified as a Beta Blocker for Drupal 8. We sat down and figured out the value proposition and amount of work (story points) for this issue.

Value and Story points are in the scale of fibonacci. Our minimum is 1, our maximum is 21. The higher, the more value or work a certain issue has.

Value: 8
Story Points: 13

Comments

drunken monkey created an issue. See original summary.

drunken monkey’s picture

Issue summary: View changes
stborchert’s picture

Status: Active » Needs review
StatusFileSize
new25.54 KB

Ok, lets start with the tests to see which direction this takes ...

borisson_’s picture

There is a bunch of places in the patch where you change array to [], Search API only uses the long array notation. If you can revert that change it'll be easier to see what changes are actually needed here.

borisson_’s picture

Status: Needs review » Needs work

back to NW.

stborchert’s picture

Status: Needs work » Needs review
StatusFileSize
new18.08 KB

Ok, changed short array syntax back to long arrays.

borisson_’s picture

Status: Needs review » Needs work

I think this looks good and I like that there's additional testcoverage. I did find some things that can be improved.

  1. +++ b/src/Plugin/search_api/processor/Tokenizer.php
    @@ -175,19 +175,36 @@ class Tokenizer extends FieldsProcessorPluginBase {
    -  protected function processFieldValue(&$value, &$type) {
    +  public function processFieldValue(&$value, &$type) {
    

    Why is this now a public method?

  2. +++ b/src/Processor/FieldsProcessorPluginBase.php
    @@ -292,11 +292,11 @@ abstract class FieldsProcessorPluginBase extends ProcessorPluginBase {
    +   * @param mixed $value
    +   *   The string value or an array of string values to preprocess, as a
    +   *   reference. Can be manipulated directly, nothing has to be returned.
    +   *   The values can either be left a string, or changed into an array of
    +   *   tokens. A token is an associative array containing:
    

    Let's make this more explicit, it's string|string[].

  3. +++ b/src/Processor/FieldsProcessorPluginBase.php
    @@ -348,10 +348,11 @@ abstract class FieldsProcessorPluginBase extends ProcessorPluginBase {
    +   * @param mixed $value
    

    Again, string|string[]

  4. +++ b/src/Plugin/search_api/processor/HtmlFilter.php
    @@ -136,6 +136,21 @@ class HtmlFilter extends FieldsProcessorPluginBase {
    +    if (!is_array($value)) {
    +      $this->_processFieldValue($value, $type);
    +      return;
    +    }
    +    foreach ($value as &$field_value) {
    +      $this->_processFieldValue($field_value, $type);
    +    }
    

    This is the only method where an early return is added, let's put the foreach in an else statement; like the other processors

stborchert’s picture

Status: Needs work » Needs review
StatusFileSize
new17.96 KB

Uh, I forgot to change the function visibility back after some debugging attempts ...

Added your changes.

borisson_’s picture

Status: Needs review » Reviewed & tested by the community

I think this looks great, let's see what @drunken_monkey thinks about this patch. The added testcases are awesome!

stborchert’s picture

Uhm, but it's not complete, yet :)
I will have look into search_api_db to see, what has to be done there.

borisson_’s picture

Status: Reviewed & tested by the community » Needs work

Alright, setting back to NW.

stborchert’s picture

Status: Needs work » Needs review
StatusFileSize
new26.61 KB

Next round.
I updated the tests for search_api_db and think, it's complete now. Please note that "NOT BETWEEN" doesn't seem supported by Drupal core itself yet. I've created an issue to see, if we could add it (#2686483: Add support for database condition operator "NOT BETWEEN").

Additional question: do we want to prefix the assertion messages (i.e. within \Kernel\BackendTest) with at least the function name? Because the test uses only one test function (testFramework()) it is very hard to debug, which specific test fails.

stborchert’s picture

StatusFileSize
new7.71 KB

Forgot the interdiff.

drunken monkey’s picture

Awesome job, thanks a lot!
I'll try to take a closer look and provide a detailed review later this week.

Additional question: do we want to prefix the assertion messages (i.e. within \Kernel\BackendTest) with at least the function name? Because the test uses only one test function (testFramework()) it is very hard to debug, which specific test fails.

Doesn't it report the line number anyways?
From what I remember, I never had a problem with this yet.

stborchert’s picture

Doesn't it report the line number anyways?

Unfortunately it always prints line 93 (function stub of testFramework()).

drunken monkey’s picture

StatusFileSize
new19.61 KB
new21.04 KB

Thanks again a lot for your work!

After a bit of reviewing, this still looks very good. The main issue I found was that the processor plugins shouldn't have to change – that's what our FieldsProcessorPluginBase class is there for. I fixed that in the attached patch.
Otherwise, it's mostly a bit of re-phrasing or reformatting.

Anyways, please test/review!

Status: Needs review » Needs work

The last submitted patch, 16: 2624870-16--in_and_between_operators.patch, failed testing.

The last submitted patch, 16: 2624870-16--in_and_between_operators.patch, failed testing.

drunken monkey’s picture

Status: Needs work » Needs review
StatusFileSize
new5.09 KB
new15.95 KB

This should fix it.
Tests/reviews still welcome!

Status: Needs review » Needs work

The last submitted patch, 19: 2624870-19--in_and_between_operators.patch, failed testing.

The last submitted patch, 19: 2624870-19--in_and_between_operators.patch, failed testing.

rosinegrean’s picture

Status: Needs work » Needs review
StatusFileSize
new15.54 KB

Hello,

I've re created the patch. It applies now.
Here it goes.

Status: Needs review » Needs work

The last submitted patch, 22: 2624870-22--in_and_between_operators.patch, failed testing.

The last submitted patch, 22: 2624870-22--in_and_between_operators.patch, failed testing.

rosinegrean’s picture

Status: Needs work » Needs review
StatusFileSize
new15.86 KB

Sorry, here goes again.

drunken monkey’s picture

Title: Add operators for (NOT) IN and (NOT) BETWEEN » Add operators for (NOT) IN and BETWEEN
StatusFileSize
new15.79 KB

Thanks a lot!
You just seem to have introduced a small whitespace error – patch without it attached.

Can you otherwise confirm that the patch works as expected and looks good, code-wise?
Anyone else want to test/review?

Do we want to also adapt our Views filter plugins here to include those operators, or should we create a follow-up issue for that? (If the patch is otherwise RTBC, I guess a follow-up makes more sense, before the patch becomes out-dated again.)

borisson_’s picture

Status: Needs review » Reviewed & tested by the community

I think it looks great code-wise, pretty sure that the views part can be a follow-up.

drunken monkey’s picture

StatusFileSize
new15.52 KB

Too late, already needed a re-roll!
But if the test bot is still happy, I'll just commit it.

drunken monkey’s picture

Status: Reviewed & tested by the community » Fixed

OK, committed!
I agree with you regarding a follow-up, here it is: #2695627: Add support for (NOT) IN and BETWEEN operators to Views.
Especially a good choice not doing this here because this one is a beta blocker, but the follow-up could even wait until after stable.

In any case, thanks again everyone in here – especially stBorchert, of course!

drunken monkey’s picture

Status: Fixed » Active

I want to re-open this to discuss whether we don't want to add a "NOT BETWEEN" operator after all. That the operator isn't directly supported by the Drupal database layer isn't really an argument: the DB backend would just have to re-write the condition in a more complex way, but I don't think it's impossible (or even difficult) to do.
All other backends don't have the luxury of using operators as-is anyways, and without adding the operator I don't think developers can emulate that logic "manually" (like they could for IN, for instance).

Any other opinions?

mkalkbrenner’s picture

I now added the support for BETWEEN to the Solr backend as well.

But I'm against "NOT BETWEEN" because the programmer who requires that should be able to do the required conversion by himself using the existing operators, for example BETWEEN a,b OR BETWEEN c,d instead of
BETWEEN a,d AND NOT BETWEEN b,c.

drunken monkey’s picture

But if you don't have a given range, there's no way to re-write this correctly. Also, it's not possible to use that in, e.g., a Views filter, and the Search API isn't just meant for developers.

mkalkbrenner’s picture

If you really like, you can add NOT BETWEEN.
For sure we could handle this in the solr backend as well, even if the query API isn't intuitive for people coming from Solr. I feels more like SQL. Personally I don't like that direction, but that's just me ;-)

drunken monkey’s picture

Title: Add operators for (NOT) IN and BETWEEN » Add operators for (NOT) IN and (NOT) BETWEEN
Status: Active » Needs review
StatusFileSize
new10.1 KB

If you really like, you can add NOT BETWEEN.

Thanks, that's very generous of you!

Patch attached. As mentioned, it's also not quite as simple in the DB backend, unfortunately, but not too complicated either.

Status: Needs review » Needs work

The last submitted patch, 35: 2624870-35--not_between_operator.patch, failed testing.

drunken monkey’s picture

Status: Needs work » Needs review
StatusFileSize
new958 bytes
new10.13 KB
drunken monkey’s picture

Needed a re-roll.

drunken monkey’s picture

StatusFileSize
new9.96 KB

  • drunken monkey committed 3fb355f on 8.x-1.x
    Follow-up to #2624870 by drunken monkey: Added a "NOT BETWEEN" operator...
drunken monkey’s picture

Status: Needs review » Fixed

Committed.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

R.Muilwijk’s picture

I run into a problem with the IN operator using the database backend:

1) Add ViewsData for a search_api_field to InOperator:

function mymodule_views_data_alter(array &$data) {
  $tables = array(
    'search_api_entity_node',
    'search_api_index_site_search',
    'search_api_datasource_site_search_entity_node',
    'node__field_afdeling',
  );
  foreach ($tables as $table) {
    $data[$table]['field_afdeling']['filter']['id'] = 'in_operator';
    $data[$table]['field_afdeling']['filter']['options callback'] = 'mymodule_afdelingen_options';
    $data[$table]['field_afdeling']['filter']['allow empty'] = TRUE;
  }
}

2. Now expose the field in views and it's a select (or multiselect).

3. The error I get is: Unknown operator 'in' used in search query condition.

The BackendPluginBase::validateOperator validates on 'IN' and not on 'in'.