• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
ActiveRecord & ARel
 

ActiveRecord & ARel

on

  • 7,081 views

 

Statistics

Views

Total Views
7,081
Views on SlideShare
7,075
Embed Views
6

Actions

Likes
10
Downloads
50
Comments
0

2 Embeds 6

http://duckduckgo.com 3
https://twitter.com 3

Accessibility

Categories

Upload Details

Uploaded via as Microsoft PowerPoint

Usage Rights

CC Attribution-NonCommercial-ShareAlike LicenseCC Attribution-NonCommercial-ShareAlike LicenseCC Attribution-NonCommercial-ShareAlike License

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    ActiveRecord & ARel ActiveRecord & ARel Presentation Transcript

    • ActiveRecord & ARel Awkward friends
    • ARel is not ...
      • A replacement for ActiveRecord!
    • ARel is ...
        • Active Relation
        • Really neat
        • Still under development
        • The safest way to write SQL
        • SQL engine agnostic!
        • An OOP interpretation of Relational Algebra
        • A DSL
        • Docs? Documentation? Uh, he's sick.
        • Use it!
        • All examples assume PSQL
    • How to use ARel
      • ARel can be used independently of ActiveRecord, but I'm not going to focus on that, because it's not my use case.
      • The easiest way to use ARel, with ActiveRecord, is to access the #arel_table of your ActiveRecord models. This method exposes the Arel::Table object associated with your model. Through this object you can do many ARel-y things.
      • There are a few other class level methods, which will be covered in a bit.
    • Accessing attributes
        • Model.arel_table[:attr]
        • Model.arel_table[:attr]. as("alias").to_sql
      • The essential building block for AR & AR interaction. All of the model's attributes are available as keys to the arel_table.
      • "model"."attr" AS alias
      • Notice the result is canonically referenced and properly quoted (very portable)
    • Predicates
        • Model.arel_table[:id]. eq (1).to_sql
        • Model.arel_table[:id]. not_eq (1).to_sql
        • Model.arel_table[:id]. in ([1,2]).to_sql
        • Model.arel_table[:id]. not_in ([1,2]). to_sql
        • Model.arel_table[:name]. matches ("a%"). to_sql
        • Model.arel_table[:name]. does_not_match ("a%").to_sql
        • Model.arel_table[:id]. gt (1).to_sql
        • Model.arel_table[:id]. gteq (1).to_sql
        • Model.arel_table[:id]. lt (1).to_sql
        • Model.arel_table[:id]. lteq (1).to_sql
        • "model"."id" = 1
        • "model"."id" != 1
        • "model"."id" IN (1,2)
        • "model"."id" NOT IN (1,2)
        • "model"."name" ILIKE "a%"
        • "model"."name" NOT ILIKE "a%"
        • "model"."id" > 1
        • "model"."id" >= 1
        • &quot;model&quot;.&quot;id&quot; < 1
        • &quot;model&quot;.&quot;id&quot; <= 1
    • Predicate alternates
      • Each basic predicate supports two additional types, _any and _all . These methods each accept arrays of values, ie
      • Model.arel_table[:id]. eq_any ([1,2]).to_sql
      • => SELECT &quot;models&quot;.* FROM &quot;models&quot; WHERE (&quot;models&quot;.&quot;id&quot; = 1 OR &quot;models&quot;.&quot;id&quot; = 2)
      • Model.arel_table[:id]. in_all ([[1,2],[3,4]]).to_sql
      • => SELECT &quot;models&quot;.* FROM &quot;models&quot; WHERE (&quot;models&quot;.&quot;id&quot; IN (1,2) AND &quot;models&quot;.&quot;id&quot; IN (3,4))
    • Aggregate Functions
        • Model.arel_table[:int]. average .to_sql
        • Model.arel_table[:int]. average .as(&quot;alias&quot;).to_sql
        • Model.arel_table[:int]. count .to_sql
        • Model.arel_table[:int]. count .as(&quot;alias&quot;).to_sql
        • Model.arel_table[:int]. maximum .to_sql
        • Model.arel_table[:int]. minimum .to_sql
        • Model.arel_table[:int]. sum .to_sql
        • AVG (&quot;models&quot;.&quot;int&quot;) AS avg_id
        • AVG (&quot;models&quot;.&quot;int&quot;) AS alias
        • COUNT (&quot;models&quot;.&quot;int&quot;)
        • COUNT (&quot;models&quot;.&quot;int&quot;) AS alias
        • MAX (&quot;models&quot;.&quot;int&quot;) AS max_id
        • MIN (&quot;models&quot;.&quot;int&quot;) AS min_id
        • SUM (&quot;models&quot;.&quot;int&quot;) AS sum_id
    • Infix operators
      • m = Model.arel_table
        • m[:int1] + m[:int2]
        • m[:int1] - m[:int2]
        • m[:int1] * m[:int2]
        • m[:int1] * m[:int2].as &quot;int&quot;
        • m[:int1] / m[:int2]
        • m[:int1] / m[:int2].as &quot;int&quot;
        • Model.select( m[:int1] * m[:int2].     as(&quot;product&quot;)).to_sql
      • No support for bitwise operators or aliasing addition / subtraction
        • (int1 + int2)
        • (int1 - int2)
        • int1 * int2
        • int1 * int2 AS int
        • int1 / int2
        • int1 / int2 AS int
        • SELECT &quot;models&quot;.&quot;int1&quot; * &quot;models&quot;.&quot;int2&quot; AS product FROM &quot;models&quot;
    • Mixing ActiveRecord & ARel Where inconsistencies collide
    • Selecting results
      • m = Model.arel_table
        • Model.select( [ m[:id], m[:name] ). to_sql
        • Model. select( m[:int1].average.as(&quot;int1&quot; )). to_sql
        • Model.select( m[:int1] + m[:int2] ).to_sql
        • SELECT &quot;models&quot;.&quot;id&quot;, &quot;models&quot;.&quot;name&quot; FROM &quot;models&quot;
        • SELECT AVG(&quot;models&quot;.&quot;int1&quot;) AS int1 FROM &quot;models&quot;
        • SELECT (&quot;models&quot;.&quot;int1&quot; + &quot;models&quot;.&quot;int2&quot;) FROM &quot;models&quot;
    • Filtering results (where)
      • m = Model.arel_table
        • Model.where( m[:id].gteq(10) ). to_sql
        • Model.where( m.grouping( m[:id].gt(10).  and(m[:name].matches(&quot;foo%&quot;)). or(m[:int1].in([1,2])) )
        • Model.where( m[:int1] + m[:int2].gteq(100) )
        • SELECT &quot;models&quot;.* FROM &quot;models&quot; WHERE &quot;models&quot;.&quot;id&quot; >= 10
        • SELECT &quot;models&quot;.* FROM &quot;models&quot; WHERE ( (( &quot;models&quot;.&quot;id&quot; > 10 AND &quot;models&quot;.&quot;name&quot; ILIKE &quot;foo%&quot;) OR &quot;models&quot;.&quot;int1&quot; IN (1,2)) )
        • SELECT &quot;models&quot;.* FROM &quot;models&quot; WHERE &quot;models&quot;.&quot;int1&quot; +  &quot;models&quot;.&quot;int2&quot; >= 100
    • Grouping and Having results
        • ARel
          • Model.select( m[:name] ). group( m[:name] ).to_sql
        • ActiveRecord
          • Model.select( :name ). group( :name ).to_sql
      • The ARel methods are important, because ActiveRecord does not canonically reference fields
        • SELECT &quot;models&quot;.&quot;name&quot;   FROM &quot;models&quot;  GROUP BY &quot;models&quot;.&quot;name&quot;
        • SELECT name FROM &quot;models&quot;  GROUP BY name
    • Ordering results
      • m = Model.arel_table
        • m[:id]. asc
        • m[:id]. desc
        • m[:string]. lower
        • ARel
          • Model.order( m[:id].asc ). to_sql
        • ActiveRecord
          • Model.order( :id ).to_sql
      • The ARel methods are important, because ActiveRecord does not canonically reference fields
        • &quot;models&quot;.&quot;id&quot; ASC
        • &quot;models&quot;.&quot;id&quot; DESC
        • LOWER (&quot;models&quot;.&quot;string&quot;)
        • SELECT &quot;models&quot;.* FROM &quot;models&quot; ORDER BY &quot;models&quot;.&quot;id&quot; ASC
        • SELECT &quot;models&quot;.*  FROM &quot;models&quot;  ORDER BY id
    • Limiting results
        • Model. skip (10).to_sql
        • Model. take (100).to_sql
        • Model. skip (10). take (100). to_sql
      • Take must be the last method in the chain, always.
        • SELECT &quot;models&quot;.* FROM &quot;models&quot; OFFSET 10
        • SELECT &quot;models&quot;.* FROM &quot;models&quot; LIMIT 100
        • SELECT &quot;models&quot;.* FROM &quot;models&quot; LIMIT 100 OFFSET 10
    • Sub Selects
      • sub = Models.joins(:others).
      •       as(&quot;alias&quot;)
      • Models.select('*').from(sub).
      • to_sql
      • SELECT * 
      • FROM (
      •   SELECT &quot;models&quot;.* 
      •   FROM &quot;models&quot; 
      •     INNER JOIN &quot;others&quot; ON 
      •       &quot;others&quot;.&quot;model_id&quot; =    
      •       &quot;models&quot;.&quot;id&quot;
      • ) alias
    • Unions
      • m = Model.arel_table
      • o = Other.arel_table
        • Model.select(m[:id]).union( Other.select(o[:id])).to_sql
        • ( SELECT &quot;models&quot;.&quot;id&quot; FROM &quot;models&quot; UNION SELECT &quot;others&quot;.&quot;id&quot; FROM &quot;others&quot; )
    • Complex joins
      • Polymorphic join
      • m = Model.arel_table
      • o = Other.arel_table
      • sql =  m.joins(o).on(
      •     m[:id].eq(o[:able_id]).
      •     and(o[:able_type].eq(&quot;O&quot;))
      •   ).to_sql
      • Model.joins(sql).to_sql
      • SELECT &quot;models&quot;.*
      • FROM &quot;models&quot;
      •   INNER JOIN &quot;others&quot; ON     (&quot;models&quot;.&quot;id&quot; = 
      •         &quot;others&quot;.&quot;able_id&quot;
      •       AND
      •       &quot;others&quot;.&quot;able_type&quot; = 
      •         &quot;O&quot;
      •       )
    • Arbitrary SQL functions
      • m = Model.arel_table
        • Model.select( Arel::Nodes::NamedFunction.new( :coalesce, [m[:id], 0])).to_sql
        • Model.select( Arel::Nodes::NamedFunction.new( :coalesce, [m[:id], 0], &quot;foo&quot;)). to_sql
        • SELECT coalesce(&quot;models&quot;.&quot;id&quot;, 0) FROM &quot;models&quot;
        • SELECT coalesce(&quot;models&quot;.&quot;id&quot;, 0)   AS foo FROM &quot;models&quot;
    • Easier Arbitrary SQL Functions
      • config/initializers/arel_extensions.rb
      • Arel::Table.class_eval do |base|
      •   def function(name, expr, aliaz = nil)
      •     Arel::Nodes::NamedFunction.new(name, expr, aliaz)
      •   end
      • end
      • m = Model.arel_table
      • Model.select(m.function(:coalesce, [m[:id], 0], &quot;foo&quot;))
    • Peeking and poking
      • m = Model.arel_table
      • query = Model.   joins(:others).
      •   merge(Other.where(id: 1)).   order(m[:id].desc).
      •   skip(10).
      •   take(100)
        • query. join_sql
        • query. where_sql
        • query. to_sql
        • INNER JOIN &quot;others&quot; ON &quot;models&quot;.&quot;id&quot; = &quot;others&quot;.&quot;model_id&quot;
        • WHERE (&quot;others&quot;.&quot;id&quot; = 1)
        • SELECT &quot;models&quot;.* FROM &quot;model&quot;   INNER JOIN &quot;others&quot; ON   &quot;models&quot;.&quot;id&quot; =   &quot;others&quot;.&quot;model_id&quot; WHERE (&quot;others&quot;.&quot;id&quot; = 1) ORDER BY &quot;models&quot;.&quot;id&quot; DESC OFFSET 10 LIMIT 100
    • Links
        • http://magicscalingsprinkles.wordpress.com/2010/01/28/why-i-wrote-arel/
        • https://github.com/rails/arel
        • http://www.railsdispatch.com/posts/activerelation
        • http://m.onkey.org/active-record-query-interface
        • http://www.bigbinary.com/videos/5-how-arel-works
        • https://github.com/stevecj/arel-presentation-slides/blob/master/one/01_slide.md
        • http://railscasts.com/episodes/215-advanced-queries-in-rails-3