Rails 7: ArelにSQLのFILTER句のサポートが追加(翻訳)
Arelについて
ArelはRuby向けのSQLジェネレータライブラリです。SQLのAST(抽象構文木: Abstract Syntax Tree)アプローチを用いて、複雑なSQLクエリを意味のわかる再利用可能な形で記述できます。
数式の表現に式木(Expression Tree)を使うのと同様に、ArelではSQL構文をノードとして表現します。
Arelでは、count
、eq
、not_eq
、gt
といったさまざまな述語(式木の演算子に相当)を用いてSQLをビルドします。
t = User.arel_table
User.where(t[:first_name].eq('Rohit')).to_sql
#=> "SELECT \"users\".* FROM \"users\" WHERE \"users\".\"first_name\" = 'Rohit'"
t.
SQLのFILTER句について
SQLのFILTER句は、sum
やavg
やcount
などの集約関数をWHERE句で拡張します。
COUNT(<式>) FILTER(WHERE <条件>)
Rails 7でFILTERの2項予測(binary prediction)のサポートが追加され、Arelでこのfilter
句をサポートおよび生成できるようになりました(#40491)。
改修前
t = User.arel_table
Arel.star.count.filter(t[:first_name].eq("Rohit")).to_sql
#=> NoMethodError: undefined method `filter' for #<Arel::Nodes::Count:0x00007f7f71fd1dd8>
改修後
t = User.arel_table
Arel.star.count.filter(t[:first_name].eq("Rohit")).to_sql
#=> "COUNT(*) FILTER (WHERE \"users\".\"first_name\" = 'Rohit')"
t = Order.arel_table
t[:amount].sum.filter(t(:item_count).lt(2)).to_sql
#=> "SUM(\"orders\".\"amount\") FILTER (WHERE \"orders\".\"item_count\" < 2)"
# With alias
t[:amount].sum.filter(t[:item_count].lteq(3).as('small_orders_total_amount')).to_sql
#=> "SUM(\"orders\".\"amount\") FILTER (WHERE \"orders\".\"item_count\" <= 3 AS small_orders_total_amount)"
原注: このFILTER句を現在サポートしているデータベースは、PostgreSQL(9.4以降)およびSQLite(3.30以降)です。
概要
元サイトの許諾を得て翻訳・公開いたします。
この改修は、7-0-stableにマージ済みです。