pgrel icon indicating copy to clipboard operation
pgrel copied to clipboard

[feature request] Add support for operators in JSONB path query

Open jonian opened this issue 5 years ago • 7 comments

Hi @palkan, thanks for this gem. It seems that it is not possible to define operators when doing a JSONB path query. The operator is guessed from the value provided and it uses = or IN. Is this correct?

I was thinking of adding support using one of the examples below:

# Convert path to chain
Model.store(:store).path.like(:name, '%test%')

# Pass operator as option
Model.store(:store).path(:name, '%test%', operator: 'ILIKE')

# Pass arel node as first argument
Model.store(:store).path(Arel::Nodes::Matches, :name, '%test%')

What do you think? I've implemented the first example in my application and if you agree I can make a PR.

jonian avatar Dec 20 '20 17:12 jonian

What about:

Model.store(:store).path(:name).like('%test%')

?

And I like this option, too:

Model.store(:store).path(:name, '%test%', operator: 'ILIKE')

# or
Model.store(:store).path(:name).op("ILIKE", '%test%')

It could be used for arbitrary operators.

palkan avatar Dec 22 '20 14:12 palkan

Thanks for the response, I'm ok with any of them. I think the best are:

# will also need methods for unlike, gt, gte, lt, lte
Model.store(:store).path(:name).like('%test%')

Model.store(:store).path(:name).op("ILIKE", '%test%')

Both can be implemented to give more options and avoid SQL operators for the common cases that are covered by the first option.

As I said in my previous comment, I can make a PR for this when you decide what to implement.

jonian avatar Dec 22 '20 14:12 jonian

After thinking about this a little bit more, I think that converting path to a chain, will require to change the way that path works now, so the best way to do it seems to add the operators in the store chain.

Convert path to chain

# using 
Model.store(:store).path(:name).like('%test%')
Model.store(:store).path(:name).op("ILIKE", '%test%')

# will require to check for `=` with
Model.store(:store).path(:name).eq('test')
Model.store(:store).path(:name).op("=", 'test')

Add operator methods to store chain

# current usage
Model.store(:store).path(:name, 'test')
Model.store(:store).not.path(:name, 'test')

# usage with specific operators
Model.store(:store).like.path(:name, '%test%')
Model.store(:store).not.like.path(:name, '%test%')

# usage with arbitary operator
Model.store(:store).op("LIKE").path(:name, '%test%')
Model.store(:store).not.op("LIKE").path(:name, '%test%')

What do you think?

jonian avatar Dec 22 '20 15:12 jonian

path(...).like(...) looks more natural than like(...).path(...)

Though converting path into a chain would be hard since we allow arbitrary number of args 🤔

Maybe, we can introduce a new method, say, #at_path:

Model.store(:store).at_path(:name).like('%test%')

palkan avatar Dec 23 '20 13:12 palkan

To summarize, the available options that are easier to implement and do not require changes in how the gem already works are:

# New operators are always a chain
Model.store(:store).like.path(:name, '%test%')

# Path is a chain when no arguments given
Model.store(:store).path.like(:name, '%test%')

# New method for path chain
Model.store(:store).at_path(:name).like('%test%')

I think all options are good and the decision is up to you @palkan.

jonian avatar Dec 24 '20 10:12 jonian

Let's continue with the last one: #at_path.

palkan avatar Dec 28 '20 12:12 palkan

Great! I will start working on it in the next days.

jonian avatar Dec 28 '20 17:12 jonian