On Thursday, January 24, 2019 at 4:49:56 PM UTC-8, Janko Marohnić wrote:
>
> Hello again,
>
> Recently I was writing a query with the ANY Postgres operator, and was 
> trying out the following:
>
>   DB[:table].where{"string" =~ ANY(DB[:some_dataset].select(:value))}
>
> The query wasn't working, and then I realized it's because Sequel had 
> swapped the arguments:
>
>   SELECT * FROM table WHERE (ANY((SELECT value FROM some_dataset)) = 
> 'string')
>
> And the ANY operator requires the value to be on the left-hand side. 
> Anyway, creating an expression object from the string worked:
>
>   DB[:table].where{Sequel["string"] =~ 
> ANY(DB[:some_dataset].select(:value))}
>   # SELECT * FROM table WHERE ('string' = ANY((SELECT value FROM 
> some_dataset)))
>
> From the source code I'm not sure why using implicit coercion didn't work. 
> But I don't think I'm understanding it correctly, because I was expecting 
> to find #coerce method defined for various types of operands, but I only 
> found it Numeric objects in SQL::NumericExpression. Since I didn't find 
> #coerce method for Strings, I would expect an exception to be raised, not 
> that it still works but with reversed order of operands.
>
> My question is whether there is something that can be modified in Sequel 
> to have it support that correctly (maybe adding a #coerce method for 
> Strings to SQL::StringMethods?). I would gladly submit a PR.
>
> I noticed some other inconsistencies as well:
>
>   DB[:table].where("string" =~ Sequel[:column]) # this is what we've seen 
> before
>   # SELECT * FROM table WHERE (column = 'string')
>   DB[:table].where(1 =~ Sequel[:column])
>   # SELECT * FROM table WHERE NULL
>
>   DB[:table].where(1 >= Sequel[:column])
>   # SELECT * FROM table WHERE (1 >= column)
>   DB[:table].where("string" >= Sequel[:column])
>   #~> ArgumentError: comparison of String with Sequel::SQL::Identifier 
> failed
>
> Actually, now that I've dug into operators and coercion a bit more, it 
> seems that Ruby language itself is shockingly inconsistent in this area. 
> I've created a gist 
> <https://gist.github.com/janko-m/fcd843fa2e1743b0ad10500e4094d2ba> showing 
> the inconsistency.
>

#coerce only applies to numeric operations in Ruby, you shouldn't expect it 
to apply to String.

What you are running into is "x" =~ foo calls foo =~ "x" 
(https://ruby-doc.org/core-2.2.0/String.html#method-i-3D~).  And 
Sequel::SQL::Function#=~ uses an equality expression.  Sequel cannot know 
that you called "x" =~ foo instead of foo =~ "x", so that case cannot be 
handled correctly.  You've already figured out that you can turn the string 
into a Sequel expression to work around the issue.  You could also use the 
hash syntax:

  DB[:table].where("string" => Sequel.function(:ANY, 
DB[:some_dataset].select(:value)))

Thanks,
Jeremy

-- 
You received this message because you are subscribed to the Google Groups 
"sequel-talk" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/sequel-talk.
For more options, visit https://groups.google.com/d/optout.

Reply via email to