Squeelから移行するときに地獄を見て、ほとんどやけくそ気味にいろいろ試したらできた備忘録。
頭が悪いクエリで恐縮だが、シンプルな例として「IDが1または2」という条件をwhereの外部から与える場合について考える。
今はなきsqueelの場合
where = { id: 1 } | { id : 2 }
User.where(where).to_sql
実はこのコードを今動かしたところ、 |
がSyntaxエラーを起こして動かない。これに近いクエリが今まで何故動いていたのかわからず戦慄する。
実際のコードではif文の条件付きで連結されていたが、連結したら動かなかったのではないかとすら思わせられる。
さすがに今からこれを検証する気は起きないので、これが動く環境があったのかもねくらいに捉えていただきたい。
baby_squeelの場合
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でラムダ式を使う場合
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にはそのようなロジックが見当たらないのでラムダ式かつ引数ゼロの場合に正しく解釈できなかったのかはそこらへんが関係しているのだろうか。今度読む。