Upgrade to Pro — share decks privately, control downloads, hide ads and more …

ActiveRecord + Range

Avatar for ur5us ur5us
December 01, 2021

ActiveRecord + Range

Use Ruby Range to simplify ActiveRecord queries but watch out for some gotchas.

Avatar for ur5us

ur5us

December 01, 2021

Other Decks in Programming

Transcript

  1. Let’s take a look at Ruby’s Range ` ` 1..5

    => 1..5 (1..5).include?(3) => true (1..5).include?(5) => true (1..5).include?(6) => false (1..5).to_a => [1, 2, 3, 4, 5] (1...5).include?(5) => false (1...5).to_a => [1, 2, 3, 4]
  2. Begin-/Endless Ranges 1.. => 1.. ← endless range, added in

    Ruby 2.6 1... => 1... ← also endless range # but not equal, although technically representing the same sequence! (1..) == (1...) => false ..1 => ..1 ← beginless range, added in Ruby 2.7 ...1 => ...1 (..1) == (...1) => false
  3. String ranges ?a..?d => "a".."d" ("a".."d").include?(?b) => true (?a..).include?(?z) #

    or (?a...).include?(?z) => true ("aa".."bb").to_a => ["aa", "ab", "ac", "ad", "ae", "af", "ag", "ah", "ai", "aj", "ak", "al", "am", "an", "ao", "ap", "aq", "ar", "as", "at", (...?z).include?(?z) => true # 🤔 Huh? # etc
  4. Object ranges 5.days.ago..3.days.from_now => Fri, 04 Jun 2021 05:33:55.797659613 UTC

    +00:00..Sat, 12 Jun 2021 05:33:55.798241168 UTC +00:00 5.days.ago...3.days.from_now => Fri, 04 Jun 2021 05:34:22.599867786 UTC +00:00...Sat, 12 Jun 2021 05:34:22.600060870 UTC +00:00 5.days.ago.. => Fri, 04 Jun 2021 05:35:13.899708237 UTC +00:00.. 5.days.ago... warning: ... at EOL, should be parenthesized? => Fri, 04 Jun 2021 05:35:15.054472243 UTC +00:00... # …and the same for beginless Object ranges
  5. Over to ActiveRecord Post( id: integer, title: string, body: text,

    user_id: integer, created_at: datetime, updated_at: datetime, published_at: datetime )
  6. Query Post.where(id: 3..).to_sql => "SELECT \"posts\".* FROM \"posts\" WHERE \"posts\".\"id\"

    >= 3" Post.where(id: 3...).to_sql => "SELECT \"posts\".* FROM \"posts\" WHERE \"posts\".\"id\" >= 3" Post.where.not(id: 3...).to_sql => "SELECT \"posts\".* FROM \"posts\" WHERE \"posts\".\"id\" < 3" Post.where(id: ..3).to_sql => "SELECT \"posts\".* FROM \"posts\" WHERE \"posts\".\"id\" <= 3" Post.where(id: ...3).to_sql => "SELECT \"posts\".* FROM \"posts\" WHERE \"posts\".\"id\" < 3" Post.where(id: 1..3).to_sql => "SELECT \"posts\".* FROM \"posts\" WHERE \"posts\".\"id\" BETWEEN 1 AND 3" Post.where(id: 1...3).to_sql => "SELECT \"posts\".* FROM \"posts\" WHERE \"posts\".\"id\" >= 1 AND \"posts\".\"id\" < 3"
  7. Now more serious Post.where(["created_at < ?", 5.days.ago]).to_sql => "SELECT \"posts\".*

    FROM \"posts\" WHERE (created_at < '2021-06-04 05:55:52.207346')" posts = Post.arel_table Post.where(posts[:created_at].lt(5.days.ago)).to_sql => "SELECT \"posts\".* FROM \"posts\" WHERE \"posts\".\"created_at\" < '2021-06-04 05:56:25.469364'"