LoginSignup
0
2

More than 5 years have passed since last update.

BabySqueelのwhere条件を外部から与える

Last updated at Posted at 2018-09-18

Squeelから移行するときに地獄を見て、ほとんどやけくそ気味にいろいろ試したらできた備忘録。

頭が悪いクエリで恐縮だが、シンプルな例として「IDが1または2」という条件をwhereの外部から与える場合について考える。

今はなきsqueelの場合

by_squeel.rb
where = { id: 1 } | { id : 2 }
User.where(where).to_sql

実はこのコードを今動かしたところ、 | がSyntaxエラーを起こして動かない。これに近いクエリが今まで何故動いていたのかわからず戦慄する。
実際のコードではif文の条件付きで連結されていたが、連結したら動かなかったのではないかとすら思わせられる。
さすがに今からこれを検証する気は起きないので、これが動く環境があったのかもねくらいに捉えていただきたい。

baby_squeelの場合

by_baby_squeel.rb
where_block = Proc.new{ (id == 1) | (id == 2) }
User.where.has(&where).to_sql
=> "SELECT \"users\".* FROM \"users\" WHERE (\"users\".\"id\" = 1 OR \"users\".\"id\" = 2)"

注目すべきはProcを使って渡すことで、ラムダ式では引数の数が合わず、 wrong number of arguments (given 1, expected 0) になるためダメだった。
つまりはProcの性質で引数の数が合っていないのを強引に解決しているようだ。明らかに力技じゃん。

[参考]Rubyの ブロック、Proc.new、lambdaの違い
https://qiita.com/ryo-ma/items/24c46592b45775e8644d

[追記]baby_squeelでラムダ式を使う場合

by_baby_squeel_using_lambda.rb
where_block = ->(dsl){ (dsl.id == 1) | (dsl.id == 2) }
User.where.has(&where).to_sql
=> "SELECT \"users\".* FROM \"users\" WHERE (\"users\".\"id\" = 1 OR \"users\".\"id\" = 2)"

引数が合わないなら合わせてみようじゃんとやってみたらこうなった。
dsl には BabySqueel::DSL のインスタンスが含まれている。まだ全然コード読めていないが、squeelのDSLはevalする際にブロックに与えられた引数によって動きが変わるようだが、BabySqueelにはそのようなロジックが見当たらないのでラムダ式かつ引数ゼロの場合に正しく解釈できなかったのかはそこらへんが関係しているのだろうか。今度読む。

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2