Skip to content

Commit 9cb81da

Browse files
committed
Introduce ActiveResource::WhereClause
Closes [rails#408][] Introduce a simple chainable `WhereClause` class inspired by [Active Record][]. All methods (including those that integrate with [Enumerable][]) are delegated to `WhereClause#all`, which itself delegates to `Base.find`. By merging parameters through `.where`-chaining, this commit supports deferred fetching: ```ruby people = Person.where(id: 2).where(name: "david") # => GET /people.json?id=2&name=david people = Person.where(id: 2).all(params: { name: "david" }) # => GET /people.json?id=2&name=david people = Person.all(from: "/records.json").where(id: 2) # => GET /records.json?id=2 ``` [rails#408]: rails#408 [Active Record]: https://github.com/rails/rails/blob/main/activerecord/lib/active_record/relation/where_clause.rb [Enumerable]: https://ruby-doc.org/3.4.1/Enumerable.html
1 parent 9c8a2ee commit 9cb81da

File tree

5 files changed

+60
-4
lines changed

5 files changed

+60
-4
lines changed

lib/active_resource.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ module ActiveResource
4646
autoload :InheritingHash
4747
autoload :Validations
4848
autoload :Collection
49+
autoload :WhereClause
4950

5051
if ActiveSupport::VERSION::STRING >= "7.1"
5152
def self.deprecator

lib/active_resource/base.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1036,13 +1036,13 @@ def last(*args)
10361036

10371037
# This is an alias for find(:all). You can pass in all the same
10381038
# arguments to this method as you can to <tt>find(:all)</tt>
1039-
def all(*args)
1040-
find(:all, *args)
1039+
def all(options = {})
1040+
WhereClause.new(self, options)
10411041
end
10421042

10431043
def where(clauses = {})
10441044
raise ArgumentError, "expected a clauses Hash, got #{clauses.inspect}" unless clauses.is_a? Hash
1045-
find(:all, params: clauses)
1045+
all(params: clauses)
10461046
end
10471047

10481048

lib/active_resource/where_clause.rb

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# frozen_string_literal: true
2+
3+
module ActiveResource
4+
class WhereClause
5+
delegate :find, to: :@resource_class
6+
delegate_missing_to :to_a
7+
8+
def initialize(resource_class, options)
9+
@resource_class = resource_class
10+
@options = options
11+
end
12+
13+
def where(clauses = {})
14+
all(params: clauses)
15+
end
16+
17+
def all(options = {})
18+
WhereClause.new(@resource_class, @options.deep_merge(options))
19+
end
20+
21+
def to_a
22+
find(:all, @options)
23+
end
24+
end
25+
end

test/cases/collection_test.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,6 @@ def test_first_or_initialize
118118
def test_where
119119
posts = PaginatedPost.where(page: 2)
120120
next_posts = posts.where(title: "Awesome")
121-
assert_kind_of PaginatedCollection, next_posts
121+
assert_kind_of PaginatedCollection, next_posts.to_a
122122
end
123123
end

test/cases/finder_test.rb

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,36 @@ def test_where_with_clauses
6363
assert_kind_of StreetAddress, addresses.first
6464
end
6565

66+
def test_where_with_multiple_where_clauses
67+
ActiveResource::HttpMock.respond_to.get "/people.json?id=2&name=david", {}, @people_david
68+
69+
people = Person.where(id: 2).where(name: "david")
70+
assert_equal 1, people.size
71+
assert_kind_of Person, people.first
72+
assert_equal 2, people.first.id
73+
assert_equal "David", people.first.name
74+
end
75+
76+
def test_where_chained_from_all
77+
ActiveResource::HttpMock.respond_to.get "/records.json?id=2", {}, @people_david
78+
79+
people = Person.all(from: "/records.json").where(id: 2)
80+
assert_equal 1, people.size
81+
assert_kind_of Person, people.first
82+
assert_equal 2, people.first.id
83+
assert_equal "David", people.first.name
84+
end
85+
86+
def test_where_with_multiple_where_clauses_triggered_by_all
87+
ActiveResource::HttpMock.respond_to.get "/records.json?id=2&name=david", {}, @people_david
88+
89+
people = Person.where(id: 2).all(from: "/records.json", params: { name: "david" })
90+
assert_equal 1, people.size
91+
assert_kind_of Person, people.first
92+
assert_equal 2, people.first.id
93+
assert_equal "David", people.first.name
94+
end
95+
6696
def test_where_with_clause_in
6797
ActiveResource::HttpMock.respond_to { |m| m.get "/people.json?id%5B%5D=2", {}, @people_david }
6898
people = Person.where(id: [2])

0 commit comments

Comments
 (0)