Skip to content

Commit

Permalink
Instead of a configurable base class, you can specifty what class to …
Browse files Browse the repository at this point in the history
…use to construct new query objects on merge/compose
  • Loading branch information
stevegeek committed Oct 4, 2024
1 parent 910886e commit 926fae7
Show file tree
Hide file tree
Showing 14 changed files with 45 additions and 30 deletions.
11 changes: 8 additions & 3 deletions lib/quo.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,16 @@ module Quo
autoload :ComposedQuery
autoload :CollectionBackedQuery

mattr_accessor :base_query_class, default: "Quo::Query"
mattr_accessor :relation_backed_query_base_class, default: "Quo::RelationBackedQuery"
mattr_accessor :collection_backed_query_base_class, default: "Quo::CollectionBackedQuery"
mattr_accessor :max_page_size, default: 200
mattr_accessor :default_page_size, default: 20

def self.base_query_class #: Quo::Query
@@base_query_class.constantize
def self.relation_backed_query_base_class #: Quo::RelationBackedQuery
@@relation_backed_query_base_class.constantize
end

def self.collection_backed_query_base_class #: Quo::CollectionBackedQuery
@@collection_backed_query_base_class.constantize
end
end
3 changes: 1 addition & 2 deletions lib/quo/collection_backed_query.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,7 @@
# rbs_inline: enabled

module Quo
# @rbs inherits Quo::Query
class CollectionBackedQuery < Quo.base_query_class
class CollectionBackedQuery < Query
prop :total_count, _Nilable(Integer)

# Wrap an enumerable collection or a block that returns an enumerable collection
Expand Down
10 changes: 5 additions & 5 deletions lib/quo/composed_query.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class << self
def inspect
left_desc = quo_operand_desc(_left_query)
right_desc = quo_operand_desc(_right_query)
klass_name = (self < Quo::RelationBackedQuery) ? Quo::RelationBackedQuery.name : Quo::CollectionBackedQuery.name
klass_name = (self < Quo::RelationBackedQuery) ? Quo.relation_backed_query_base_class.name : Quo.collection_backed_query_base_class.name
"#{klass_name}<Quo::ComposedQuery>[#{left_desc}, #{right_desc}]"
end

Expand Down Expand Up @@ -65,14 +65,14 @@ def merge_instances(left_instance, right_instance, joins: nil)
raise ArgumentError, "Cannot merge, left has incompatible type #{left_instance.class}" unless left_instance.is_a?(Quo::Query) || left_instance.is_a?(::ActiveRecord::Relation)
raise ArgumentError, "Cannot merge, right has incompatible type #{right_instance.class}" unless right_instance.is_a?(Quo::Query) || right_instance.is_a?(::ActiveRecord::Relation)
if left_instance.is_a?(Quo::Query) && right_instance.is_a?(::ActiveRecord::Relation)
return composer(left_instance.is_a?(Quo::RelationBackedQuery) ? Quo::RelationBackedQuery : Quo::CollectionBackedQuery, left_instance.class, right_instance, joins: joins).new(**left_instance.to_h)
return composer(left_instance.is_a?(Quo::RelationBackedQuery) ? Quo.relation_backed_query_base_class : Quo.collection_backed_query_base_class, left_instance.class, right_instance, joins: joins).new(**left_instance.to_h)
elsif right_instance.is_a?(Quo::Query) && left_instance.is_a?(::ActiveRecord::Relation)
return composer(right_instance.is_a?(Quo::RelationBackedQuery) ? Quo::RelationBackedQuery : Quo::CollectionBackedQuery, left_instance, right_instance.class, joins: joins).new(**right_instance.to_h)
return composer(right_instance.is_a?(Quo::RelationBackedQuery) ? Quo.relation_backed_query_base_class : Quo.collection_backed_query_base_class, left_instance, right_instance.class, joins: joins).new(**right_instance.to_h)
elsif left_instance.is_a?(Quo::Query) && right_instance.is_a?(Quo::Query)
props = left_instance.to_h.merge(right_instance.to_h.compact)
return composer((left_instance.is_a?(Quo::RelationBackedQuery) && right_instance.is_a?(Quo::RelationBackedQuery)) ? Quo::RelationBackedQuery : Quo::CollectionBackedQuery, left_instance.class, right_instance.class, joins: joins).new(**props)
return composer((left_instance.is_a?(Quo::RelationBackedQuery) && right_instance.is_a?(Quo::RelationBackedQuery)) ? Quo.relation_backed_query_base_class : Quo.collection_backed_query_base_class, left_instance.class, right_instance.class, joins: joins).new(**props)
end
composer(Quo::RelationBackedQuery, left_instance, right_instance, joins: joins).new # Both are AR relations
composer(Quo.relation_backed_query_base_class, left_instance, right_instance, joins: joins).new # Both are AR relations
end
module_function :merge_instances

Expand Down
5 changes: 3 additions & 2 deletions lib/quo/query.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,16 @@ def to_s
inspect
end

# TODO: put this in a module with the composer and merge_instances methods
# Compose is aliased as `+`. Can optionally take `joins` parameters to add joins on merged relation.
# @rbs right: Quo::Query | ActiveRecord::Relation | Object & Enumerable[untyped]
# @rbs joins: Symbol | Hash[Symbol, untyped] | Array[Symbol | Hash[Symbol, untyped]]
# @rbs return: Quo::Query & Quo::ComposedQuery
def self.compose(right, joins: nil)
super_class = if self < Quo::CollectionBackedQuery || right < Quo::CollectionBackedQuery
Quo::CollectionBackedQuery
Quo.collection_backed_query_base_class
else
Quo::RelationBackedQuery
Quo.relation_backed_query_base_class
end
ComposedQuery.composer(super_class, self, right, joins: joins)
end
Expand Down
3 changes: 1 addition & 2 deletions lib/quo/relation_backed_query.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
require "literal"

module Quo
# @rbs inherits Quo::Query
class RelationBackedQuery < Quo.base_query_class
class RelationBackedQuery < Query
# @rbs query: ActiveRecord::Relation | Quo::Query
# @rbs props: Hash[Symbol, untyped]
# @rbs &block: () -> ActiveRecord::Relation | Quo::Query | Object & Enumerable[untyped]
Expand Down
4 changes: 3 additions & 1 deletion sig/generated/quo.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,7 @@
module Quo
extend ActiveSupport::Autoload

def self.base_query_class: () -> Quo::Query
def self.relation_backed_query_base_class: () -> Quo::RelationBackedQuery

def self.collection_backed_query_base_class: () -> Quo::CollectionBackedQuery
end
3 changes: 1 addition & 2 deletions sig/generated/quo/collection_backed_query.rbs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
# Generated from lib/quo/collection_backed_query.rb with RBS::Inline

module Quo
# @rbs inherits Quo::Query
class CollectionBackedQuery < Quo::Query
class CollectionBackedQuery < Query
# Wrap an enumerable collection or a block that returns an enumerable collection
# @rbs data: untyped, props: Symbol => untyped, block: () -> untyped
# @rbs return: Quo::CollectionBackedQuery
Expand Down
1 change: 1 addition & 0 deletions sig/generated/quo/query.rbs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ module Quo

def to_s: () -> untyped

# TODO: put this in a module with the composer and merge_instances methods
# Compose is aliased as `+`. Can optionally take `joins` parameters to add joins on merged relation.
# @rbs right: Quo::Query | ActiveRecord::Relation | Object & Enumerable[untyped]
# @rbs joins: Symbol | Hash[Symbol, untyped] | Array[Symbol | Hash[Symbol, untyped]]
Expand Down
3 changes: 1 addition & 2 deletions sig/generated/quo/relation_backed_query.rbs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
# Generated from lib/quo/relation_backed_query.rb with RBS::Inline

module Quo
# @rbs inherits Quo::Query
class RelationBackedQuery < Quo::Query
class RelationBackedQuery < Query
# @rbs query: ActiveRecord::Relation | Quo::Query
# @rbs props: Hash[Symbol, untyped]
# @rbs &block: () -> ActiveRecord::Relation | Quo::Query | Object & Enumerable[untyped]
Expand Down
8 changes: 8 additions & 0 deletions test/dummy/app/queries/application_collection_query.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# frozen_string_literal: true

# This is configured as the base query class for the applications queries. See the Quo initializer
class ApplicationCollectionQuery < Quo::CollectionBackedQuery
def hello
"collection"
end
end
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# frozen_string_literal: true

# This is configured as the base query class for the applications queries. See the Quo initializer
class ApplicationQuery < Quo::Query
class ApplicationRelationQuery < Quo::RelationBackedQuery
def hello
"world"
"relation"
end
end
3 changes: 2 additions & 1 deletion test/dummy/config/initializers/quo.rb
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
Quo.base_query_class = "ApplicationQuery"
Quo.relation_backed_query_base_class = "ApplicationRelationQuery"
Quo.collection_backed_query_base_class = "ApplicationCollectionQuery"
9 changes: 5 additions & 4 deletions test/quo/composed_query_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ def setup

test "merged result is a Quo Query and inherits from configured base class" do
klass = Quo::RelationBackedQuery.wrap(::Comment.recent).compose(::Comment.not_spam)
assert_equal Quo::RelationBackedQuery, klass.superclass
assert_equal "world", klass.new.hello
assert_equal ApplicationRelationQuery, klass.superclass
assert_equal "relation", klass.new.hello
end

test "merges two Quo::Query objects" do
Expand Down Expand Up @@ -72,6 +72,7 @@ def setup
left = Quo::CollectionBackedQuery.wrap([1, 2, 3])
right = Quo::CollectionBackedQuery.wrap([4, 5, 6])
composed = left + right
assert_equal "collection", composed.new.hello
assert_equal [1, 2, 3, 4, 5, 6], composed.new.results.to_a
end

Expand Down Expand Up @@ -130,7 +131,7 @@ def setup

test "#inspect when 1 source is a query object subclass" do
merged = CommentNotSpamQuery.compose(Quo::CollectionBackedQuery)
assert_equal "Quo::RelationBackedQuery<Quo::ComposedQuery>[CommentNotSpamQuery, Quo::CollectionBackedQuery]", merged.inspect
assert_equal "ApplicationRelationQuery<Quo::ComposedQuery>[CommentNotSpamQuery, Quo::CollectionBackedQuery]", merged.inspect
end

test "#inspect when 2 collection sources are provided" do
Expand All @@ -142,7 +143,7 @@ def setup
test "#inspect when 1 source is a merged query" do
nested = CommentNotSpamQuery.compose(UnreadCommentsQuery)
merged = nested.compose(Quo::CollectionBackedQuery)
assert_equal "Quo::RelationBackedQuery<Quo::ComposedQuery>[Quo::RelationBackedQuery<Quo::ComposedQuery>[CommentNotSpamQuery, UnreadCommentsQuery], Quo::CollectionBackedQuery]", merged.inspect
assert_equal "ApplicationRelationQuery<Quo::ComposedQuery>[ApplicationRelationQuery<Quo::ComposedQuery>[CommentNotSpamQuery, UnreadCommentsQuery], Quo::CollectionBackedQuery]", merged.inspect
end

test "#copy makes a copy of this query object with different options" do
Expand Down
8 changes: 4 additions & 4 deletions test/quo/custom_base_class_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def setup
Comment.create!(post: p1, body: "abc", read: false)
Comment.create!(post: p2, body: "def", read: false, spam_score: 0.8)

@q1 = Quo::RelationBackedQuery.wrap(props: {since_date: Time}) do
@q1 = ApplicationRelationQuery.wrap(props: {since_date: Time}) do
Comment.recent(since_date)
end
@q2 = Quo::RelationBackedQuery.wrap(props: {spam_score: Float}) do
Expand All @@ -20,10 +20,10 @@ def setup
end

test "wrapped query inherits from custom base class" do
assert_kind_of ApplicationQuery, @q1.new(since_date: 1.day.ago)
assert_equal "world", @q1.new(since_date: 1.day.ago).hello
assert_kind_of ApplicationRelationQuery, @q1.new(since_date: 1.day.ago)
assert_equal "relation", @q1.new(since_date: 1.day.ago).hello

klass = Quo::RelationBackedQuery.wrap(Comment.recent).compose(Comment.not_spam)
assert_kind_of ApplicationQuery, klass.new
assert_kind_of ApplicationRelationQuery, klass.new
end
end

0 comments on commit 926fae7

Please sign in to comment.