graphiti icon indicating copy to clipboard operation
graphiti copied to clipboard

Logical `or` for filters

Open mkamensky opened this issue 6 years ago • 4 comments

I would like to have logical or between filters, for example find the users whose first or last name is "Jones". I currently use the following to simulate it:

      filter :|, :hash do
        eq do |scope, vals|
          vals.reduce(scope) do |res, fil|
            fil.reduce(res) do |scop, (k, v)|
              filt = filters[k]
              v.reduce(scop) do |cur, (op, val)|
                (
                  filt[:operators][op]&.call(base_scope, val, context) ||
                  adapter.try(
                    "filter_#{filt[:type]}_#{op}", base_scope, k, [*val]
                  )
                ).or(cur)
              end
            end
          end
        end
      end

So now I can have something like

http://localhost:3000/api/v1/employees?filter[first_name]=bob&filter[|][last_name]=sponge

But I am not sure that this works correctly (for example, with respect to restrictions on filtering), and it uses private functions. I couldn't find it in the docs, and it appears that the jsonapi spec does not specify it. Can this feature be added (if it doesn't exist)?

mkamensky avatar Feb 03 '20 18:02 mkamensky

@mkamensky There's a few ways to go about this, and depending on what you want I think this can be approached in different ways. If you specifically want to be able to filter first_name == 'foo' OR last_name == 'foo', then I would recommend adding a custom filter for that:

filter :first_or_last_name, :string do
  eq do |scope, values|
    scope.where('first_name IN (?) OR last_name IN (?)', values, values)
  end
end

If you want a more dynamic query builder which includes nested ORs and ANDs, that's something which might take a bit more thought.

wadetandy avatar Feb 06 '20 06:02 wadetandy

@wadetandy thanks, I actually want the latter, what I wrote was just an example. What I wrote above seems to work so far (I just fixed a small issue there), but I did not test it comprehensively. Also, I don't know if there is a standard syntax for this.

mkamensky avatar Feb 06 '20 13:02 mkamensky

@mkamensky we thought about this a bit before:

Screen Shot 2020-02-06 at 9 49 36 AM

I'd really, really like to see something like this in Graphiti. I think it's a powerful, defining feature that shouldn't be TOO hard to implement if you wanted to take a stab at it.

richmolj avatar Feb 06 '20 14:02 richmolj

@richmolj Thanks. This is what I was looking for, but I don't see myself implementing this in the near future, sorry... Perhaps in the meanwhile the hack above can be useful

mkamensky avatar Feb 08 '20 10:02 mkamensky