quo 1.0.0.beta2 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.devcontainer/Dockerfile +17 -0
- data/.devcontainer/compose.yml +10 -0
- data/.devcontainer/devcontainer.json +12 -0
- data/Appraisals +4 -12
- data/CHANGELOG.md +112 -1
- data/CLAUDE.md +19 -0
- data/Gemfile +7 -1
- data/LICENSE.txt +1 -1
- data/README.md +496 -203
- data/Rakefile +66 -6
- data/UPGRADING.md +216 -0
- data/badges/coverage_badge_total.svg +35 -0
- data/badges/rubycritic_badge_score.svg +35 -0
- data/claude-skill/README.md +100 -0
- data/claude-skill/SKILL.md +442 -0
- data/claude-skill/references/API_REFERENCE.md +462 -0
- data/claude-skill/references/COMPOSITION.md +396 -0
- data/claude-skill/references/PAGINATION.md +396 -0
- data/claude-skill/references/QUERY_TYPES.md +297 -0
- data/claude-skill/references/TRANSFORMERS.md +282 -0
- data/context/01-core-architecture.md +247 -0
- data/context/02-query-types-implementation.md +355 -0
- data/context/03-composition-transformation.md +441 -0
- data/context/04-pagination-results.md +485 -0
- data/context/05-testing-configuration.md +491 -0
- data/context/06-advanced-patterns-examples.md +153 -0
- data/gemfiles/rails_8.0.gemfile +10 -5
- data/gemfiles/rails_8.1.gemfile +20 -0
- data/lib/generators/quo/install/USAGE +21 -0
- data/lib/generators/quo/install/install_generator.rb +63 -0
- data/lib/quo/collection_backed_query.rb +21 -15
- data/lib/quo/collection_results.rb +1 -0
- data/lib/quo/composed_collection_backed_query.rb +42 -0
- data/lib/quo/composed_instance.rb +144 -0
- data/lib/quo/composed_query.rb +43 -178
- data/lib/quo/composed_relation_backed_query.rb +42 -0
- data/lib/quo/composing/base_strategy.rb +22 -0
- data/lib/quo/composing/class_strategy.rb +86 -0
- data/lib/quo/composing/class_strategy_registry.rb +31 -0
- data/lib/quo/composing/query_classes_strategy.rb +38 -0
- data/lib/quo/composing.rb +81 -0
- data/lib/quo/engine.rb +1 -0
- data/lib/quo/minitest/helpers.rb +14 -24
- data/lib/quo/preloadable.rb +1 -0
- data/lib/quo/query.rb +22 -5
- data/lib/quo/relation_backed_query.rb +24 -18
- data/lib/quo/relation_backed_query_specification.rb +44 -25
- data/lib/quo/relation_results.rb +1 -0
- data/lib/quo/results.rb +31 -2
- data/lib/quo/rspec/helpers.rb +15 -26
- data/lib/quo/testing/collection_backed_fake.rb +1 -0
- data/lib/quo/testing/fake_helpers.rb +30 -0
- data/lib/quo/testing/relation_backed_fake.rb +1 -0
- data/lib/quo/version.rb +1 -1
- data/lib/quo/wrapped_collection_backed_query.rb +21 -0
- data/lib/quo/wrapped_relation_backed_query.rb +21 -0
- data/lib/quo.rb +8 -0
- data/quo.png +0 -0
- data/sig/generated/quo/collection_backed_query.rbs +10 -4
- data/sig/generated/quo/collection_results.rbs +1 -0
- data/sig/generated/quo/composed_collection_backed_query.rbs +25 -0
- data/sig/generated/quo/composed_instance.rbs +61 -0
- data/sig/generated/quo/composed_query.rbs +23 -56
- data/sig/generated/quo/composed_relation_backed_query.rbs +25 -0
- data/sig/generated/quo/composing/base_strategy.rbs +16 -0
- data/sig/generated/quo/composing/class_strategy.rbs +38 -0
- data/sig/generated/quo/composing/class_strategy_registry.rbs +16 -0
- data/sig/generated/quo/composing/query_classes_strategy.rbs +24 -0
- data/sig/generated/quo/composing.rbs +40 -0
- data/sig/generated/quo/engine.rbs +1 -0
- data/sig/generated/quo/minitest/helpers.rbs +12 -0
- data/sig/generated/quo/preloadable.rbs +1 -0
- data/sig/generated/quo/query.rbs +15 -4
- data/sig/generated/quo/relation_backed_query.rbs +15 -5
- data/sig/generated/quo/relation_backed_query_specification.rbs +47 -39
- data/sig/generated/quo/relation_results.rbs +1 -0
- data/sig/generated/quo/results.rbs +11 -0
- data/sig/generated/quo/rspec/helpers.rbs +12 -0
- data/sig/generated/quo/testing/collection_backed_fake.rbs +1 -0
- data/sig/generated/quo/testing/fake_helpers.rbs +14 -0
- data/sig/generated/quo/testing/relation_backed_fake.rbs +1 -0
- data/sig/generated/quo/wrapped_collection_backed_query.rbs +13 -0
- data/sig/generated/quo/wrapped_relation_backed_query.rbs +13 -0
- data/sig/generated/quo.rbs +1 -0
- data/website/.gitignore +6 -0
- data/website/.nojekyll +0 -0
- data/website/404.html +26 -0
- data/website/Gemfile +24 -0
- data/website/_config.yml +50 -0
- data/website/_data/navigation.yml +8 -0
- data/website/_data/sidebar.yml +2 -0
- data/website/_data/social_links.yml +3 -0
- data/website/_docs/api.md +261 -0
- data/website/_docs/get-started.md +289 -0
- data/website/assets/quo.png +0 -0
- data/website/index.md +141 -0
- metadata +70 -13
- data/gemfiles/rails_7.0.gemfile +0 -15
- data/gemfiles/rails_7.1.gemfile +0 -15
- data/gemfiles/rails_7.2.gemfile +0 -15
data/lib/quo/results.rb
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
# rbs_inline: enabled
|
|
4
4
|
|
|
5
5
|
module Quo
|
|
6
|
+
# Base results wrapper providing enumeration with optional transformation
|
|
6
7
|
class Results
|
|
7
8
|
def empty? #: bool
|
|
8
9
|
!exists?
|
|
@@ -23,6 +24,23 @@ module Quo
|
|
|
23
24
|
page_count
|
|
24
25
|
end
|
|
25
26
|
|
|
27
|
+
FILTER_METHODS = %i[
|
|
28
|
+
select filter find_all reject
|
|
29
|
+
find detect
|
|
30
|
+
take_while drop_while
|
|
31
|
+
sort_by min_by max_by
|
|
32
|
+
uniq
|
|
33
|
+
].to_set.freeze
|
|
34
|
+
|
|
35
|
+
PAIR_FILTER_METHODS = %i[partition minmax_by].to_set.freeze
|
|
36
|
+
|
|
37
|
+
PASSTHROUGH_METHODS = %i[
|
|
38
|
+
any? all? none? one? include? member?
|
|
39
|
+
count tally sum
|
|
40
|
+
each_with_object inject reduce
|
|
41
|
+
map collect flat_map collect_concat filter_map
|
|
42
|
+
].to_set.freeze
|
|
43
|
+
|
|
26
44
|
# @rbs &block: (untyped, *untyped) -> untyped
|
|
27
45
|
# @rbs return: Hash[untyped, Array[untyped]]
|
|
28
46
|
def group_by(&block)
|
|
@@ -45,16 +63,20 @@ module Quo
|
|
|
45
63
|
return super unless respond_to_missing?(method)
|
|
46
64
|
|
|
47
65
|
if block
|
|
48
|
-
@configured_query.send(method, *args, **kwargs) do |*block_args|
|
|
66
|
+
raw = @configured_query.send(method, *args, **kwargs) do |*block_args|
|
|
49
67
|
x = block_args.first
|
|
50
68
|
transformed = transform? ? @transformer.call(x) : x
|
|
51
69
|
other_args = block_args[1..] || []
|
|
52
70
|
block.call(transformed, *other_args)
|
|
53
71
|
end
|
|
72
|
+
return raw if PASSTHROUGH_METHODS.include?(method)
|
|
73
|
+
return transform_pair(raw) if PAIR_FILTER_METHODS.include?(method)
|
|
74
|
+
return transform_results(raw) if FILTER_METHODS.include?(method)
|
|
75
|
+
raw
|
|
54
76
|
else
|
|
55
77
|
raw = @configured_query.send(method, *args, **kwargs)
|
|
56
|
-
# FIXME: consider how to handle applying a transformer to a Enumerator...
|
|
57
78
|
return raw if raw.is_a?(Quo::RelationResults) || raw.is_a?(::Enumerator)
|
|
79
|
+
return raw if PASSTHROUGH_METHODS.include?(method)
|
|
58
80
|
transform_results(raw)
|
|
59
81
|
end
|
|
60
82
|
end
|
|
@@ -85,5 +107,12 @@ module Quo
|
|
|
85
107
|
@transformer.call(results)
|
|
86
108
|
end
|
|
87
109
|
end
|
|
110
|
+
|
|
111
|
+
# @rbs pair: untyped
|
|
112
|
+
# @rbs return: untyped
|
|
113
|
+
def transform_pair(pair)
|
|
114
|
+
return pair unless transform?
|
|
115
|
+
pair.map { |part| transform_results(part) }
|
|
116
|
+
end
|
|
88
117
|
end
|
|
89
118
|
end
|
data/lib/quo/rspec/helpers.rb
CHANGED
|
@@ -1,40 +1,29 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# rbs_inline: enabled
|
|
4
|
+
|
|
3
5
|
require_relative "../testing/collection_backed_fake"
|
|
4
6
|
require_relative "../testing/relation_backed_fake"
|
|
7
|
+
require_relative "../testing/fake_helpers"
|
|
5
8
|
|
|
6
9
|
module Quo
|
|
7
10
|
module Rspec
|
|
11
|
+
# Test helpers for stubbing query objects in RSpec
|
|
8
12
|
module Helpers
|
|
9
|
-
|
|
10
|
-
# make it so that results of instances of this class return a fake Result object
|
|
11
|
-
# of the right type which returns the results passed in
|
|
12
|
-
if query_class < Quo::CollectionBackedQuery
|
|
13
|
-
klass = Class.new(Quo::Testing::CollectionBackedFake) do
|
|
14
|
-
if query_class < Quo::Preloadable
|
|
15
|
-
include Quo::Preloadable
|
|
13
|
+
include Quo::Testing::FakeHelpers
|
|
16
14
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
fake = ->(*kwargs) {
|
|
23
|
-
klass.new(results: results, total_count: total_count, page_count: page_count)
|
|
24
|
-
}
|
|
25
|
-
expectation = allow(query_class).to receive(:new)
|
|
26
|
-
expectation = expectation.with(with) if with
|
|
27
|
-
expectation.and_invoke(fake)
|
|
28
|
-
elsif query_class < Quo::RelationBackedQuery
|
|
29
|
-
fake = ->(*kwargs) {
|
|
30
|
-
Quo::Testing::RelationBackedFake.new(results: results, total_count: total_count, page_count: page_count)
|
|
31
|
-
}
|
|
32
|
-
expectation = allow(query_class).to receive(:new)
|
|
33
|
-
expectation = expectation.with(with) if with
|
|
34
|
-
expectation.and_invoke(fake)
|
|
35
|
-
else
|
|
15
|
+
def fake_query(query_class, with: nil, results: [], total_count: nil, page_count: nil, &block)
|
|
16
|
+
unless query_class < Quo::Query
|
|
36
17
|
raise ArgumentError, "Not a Query class: #{query_class}"
|
|
37
18
|
end
|
|
19
|
+
|
|
20
|
+
klass = build_fake_class(query_class)
|
|
21
|
+
fake = ->(*kwargs) {
|
|
22
|
+
klass.new(results: results, total_count: total_count, page_count: page_count)
|
|
23
|
+
}
|
|
24
|
+
expectation = allow(query_class).to receive(:new)
|
|
25
|
+
expectation = expectation.with(with) if with
|
|
26
|
+
expectation.and_invoke(fake)
|
|
38
27
|
end
|
|
39
28
|
end
|
|
40
29
|
end
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
module Quo
|
|
6
6
|
module Testing
|
|
7
|
+
# Test helper for creating fake collection-backed queries with predefined results
|
|
7
8
|
class CollectionBackedFake < Quo.collection_backed_query_base_class
|
|
8
9
|
prop :results, _Any, reader: false
|
|
9
10
|
prop :page_count, _Nilable(Integer), reader: false
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# rbs_inline: enabled
|
|
4
|
+
|
|
5
|
+
module Quo
|
|
6
|
+
module Testing
|
|
7
|
+
# Shared helpers for creating fake query objects in tests
|
|
8
|
+
module FakeHelpers
|
|
9
|
+
private
|
|
10
|
+
|
|
11
|
+
# @rbs query_class: Class
|
|
12
|
+
# @rbs return: Class
|
|
13
|
+
def build_fake_class(query_class)
|
|
14
|
+
if query_class < Quo::CollectionBackedQuery
|
|
15
|
+
Class.new(Quo::Testing::CollectionBackedFake) do
|
|
16
|
+
if query_class < Quo::Preloadable
|
|
17
|
+
include Quo::Preloadable
|
|
18
|
+
|
|
19
|
+
def query
|
|
20
|
+
collection
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
else
|
|
25
|
+
Quo::Testing::RelationBackedFake
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
module Quo
|
|
6
6
|
module Testing
|
|
7
|
+
# Test helper for creating fake relation-backed queries with predefined results
|
|
7
8
|
class RelationBackedFake < Quo.relation_backed_query_base_class
|
|
8
9
|
prop :results, _Any, reader: false
|
|
9
10
|
prop :page_count, _Nilable(Integer), reader: false
|
data/lib/quo/version.rb
CHANGED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# rbs_inline: enabled
|
|
4
|
+
|
|
5
|
+
module Quo
|
|
6
|
+
class WrappedCollectionBackedQuery < Quo.collection_backed_query_base_class
|
|
7
|
+
# @rbs!
|
|
8
|
+
# @wrapped: Enumerable[untyped]
|
|
9
|
+
prop :wrapped, Enumerable, writer: false
|
|
10
|
+
|
|
11
|
+
# @rbs override
|
|
12
|
+
def collection
|
|
13
|
+
wrapped
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# @rbs override
|
|
17
|
+
def inspect
|
|
18
|
+
"#{self.class.name}[#{wrapped.class.name}]"
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# rbs_inline: enabled
|
|
4
|
+
|
|
5
|
+
module Quo
|
|
6
|
+
class WrappedRelationBackedQuery < Quo.relation_backed_query_base_class
|
|
7
|
+
# @rbs!
|
|
8
|
+
# @wrapped: ActiveRecord::Relation
|
|
9
|
+
prop :wrapped, ::ActiveRecord::Relation, writer: false
|
|
10
|
+
|
|
11
|
+
# @rbs override
|
|
12
|
+
def query
|
|
13
|
+
wrapped
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# @rbs override
|
|
17
|
+
def inspect
|
|
18
|
+
"#{self.class.name}[#{wrapped.klass.name}]"
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
data/lib/quo.rb
CHANGED
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
require_relative "quo/version"
|
|
6
6
|
require "quo/engine"
|
|
7
|
+
require "literal"
|
|
7
8
|
|
|
9
|
+
# Query object library for ActiveRecord with composable queries and pagination
|
|
8
10
|
module Quo
|
|
9
11
|
extend ActiveSupport::Autoload
|
|
10
12
|
|
|
@@ -16,7 +18,13 @@ module Quo
|
|
|
16
18
|
autoload :RelationResults
|
|
17
19
|
autoload :CollectionResults
|
|
18
20
|
autoload :ComposedQuery
|
|
21
|
+
autoload :ComposedInstance
|
|
22
|
+
autoload :ComposedRelationBackedQuery
|
|
23
|
+
autoload :ComposedCollectionBackedQuery
|
|
24
|
+
autoload :WrappedRelationBackedQuery
|
|
25
|
+
autoload :WrappedCollectionBackedQuery
|
|
19
26
|
autoload :CollectionBackedQuery
|
|
27
|
+
autoload :Composing
|
|
20
28
|
|
|
21
29
|
mattr_accessor :relation_backed_query_base_class, default: "Quo::RelationBackedQuery"
|
|
22
30
|
mattr_accessor :collection_backed_query_base_class, default: "Quo::CollectionBackedQuery"
|
data/quo.png
ADDED
|
Binary file
|
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
# Generated from lib/quo/collection_backed_query.rb with RBS::Inline
|
|
2
2
|
|
|
3
3
|
module Quo
|
|
4
|
+
# Query object backed by in-memory collections
|
|
4
5
|
class CollectionBackedQuery < Query
|
|
5
|
-
#
|
|
6
|
-
# @rbs
|
|
6
|
+
# @rbs data: Enumerable[untyped] | Quo::CollectionBackedQuery
|
|
7
|
+
# @rbs props: Hash[Symbol, untyped]
|
|
8
|
+
# @rbs &block: ? () -> Enumerable[untyped]
|
|
7
9
|
# @rbs return: Quo::CollectionBackedQuery
|
|
8
|
-
def self.wrap: (?untyped data, ?props: untyped) ?{ (
|
|
10
|
+
def self.wrap: (?Enumerable[untyped] | Quo::CollectionBackedQuery data, ?props: Hash[Symbol, untyped]) ?{ () -> Enumerable[untyped] } -> Quo::CollectionBackedQuery
|
|
11
|
+
|
|
12
|
+
# @rbs enumerable: Enumerable[untyped]
|
|
13
|
+
# @rbs return: Quo::WrappedCollectionBackedQuery
|
|
14
|
+
def self.from: (Enumerable[untyped] enumerable) -> Quo::WrappedCollectionBackedQuery
|
|
9
15
|
|
|
10
16
|
# @rbs return: Object & Enumerable[untyped]
|
|
11
17
|
def collection: () -> (Object & Enumerable[untyped])
|
|
@@ -15,7 +21,7 @@ module Quo
|
|
|
15
21
|
# @rbs return: Object & Enumerable[untyped]
|
|
16
22
|
def query: () -> (Object & Enumerable[untyped])
|
|
17
23
|
|
|
18
|
-
def results: () ->
|
|
24
|
+
def results: () -> Quo::Results
|
|
19
25
|
|
|
20
26
|
# @rbs override
|
|
21
27
|
def relation?: ...
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Generated from lib/quo/composed_collection_backed_query.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
module Quo
|
|
4
|
+
class ComposedCollectionBackedQuery
|
|
5
|
+
include ComposedInstance
|
|
6
|
+
|
|
7
|
+
@left: Quo::Query | Enumerable[untyped]
|
|
8
|
+
|
|
9
|
+
@right: Quo::Query | Enumerable[untyped]
|
|
10
|
+
|
|
11
|
+
@merge_joins: Symbol | Hash[untyped, untyped] | Array[untyped] | nil
|
|
12
|
+
|
|
13
|
+
# @rbs override
|
|
14
|
+
def collection: ...
|
|
15
|
+
|
|
16
|
+
# @rbs override
|
|
17
|
+
def inspect: ...
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
# @rbs operand: untyped
|
|
22
|
+
# @rbs return: String
|
|
23
|
+
def operand_desc: (untyped operand) -> String
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Generated from lib/quo/composed_instance.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
module Quo
|
|
4
|
+
module ComposedInstance
|
|
5
|
+
# @rbs **overrides: untyped
|
|
6
|
+
# @rbs return: Quo::Query
|
|
7
|
+
def copy: (**untyped overrides) -> Quo::Query
|
|
8
|
+
|
|
9
|
+
private
|
|
10
|
+
|
|
11
|
+
# @rbs prop_name: Symbol
|
|
12
|
+
# @rbs value: untyped
|
|
13
|
+
# @rbs return: Quo::Query
|
|
14
|
+
def fan_override: (Symbol prop_name, untyped value) -> Quo::Query
|
|
15
|
+
|
|
16
|
+
# @rbs return: Array[Symbol]
|
|
17
|
+
def own_property_names: () -> Array[Symbol]
|
|
18
|
+
|
|
19
|
+
# @rbs operand: untyped
|
|
20
|
+
# @rbs prop_name: Symbol
|
|
21
|
+
# @rbs return: bool
|
|
22
|
+
def operand_accepts?: (untyped operand, Symbol prop_name) -> bool
|
|
23
|
+
|
|
24
|
+
# @rbs operand: untyped
|
|
25
|
+
# @rbs prop_name: Symbol
|
|
26
|
+
# @rbs value: untyped
|
|
27
|
+
# @rbs return: untyped
|
|
28
|
+
def apply_to_operand: (untyped operand, Symbol prop_name, untyped value) -> untyped
|
|
29
|
+
|
|
30
|
+
# @rbs return: ActiveRecord::Relation | Enumerable[untyped]
|
|
31
|
+
def merge_left_and_right: () -> (ActiveRecord::Relation | Enumerable[untyped])
|
|
32
|
+
|
|
33
|
+
# @rbs operand: untyped
|
|
34
|
+
# @rbs return: ActiveRecord::Relation | Enumerable[untyped]
|
|
35
|
+
def unwrap_operand: (untyped operand) -> (ActiveRecord::Relation | Enumerable[untyped])
|
|
36
|
+
|
|
37
|
+
# @rbs left_rel: ActiveRecord::Relation
|
|
38
|
+
# @rbs right_rel: ActiveRecord::Relation
|
|
39
|
+
# @rbs return: ActiveRecord::Relation
|
|
40
|
+
def merge_active_record_relations: (ActiveRecord::Relation left_rel, ActiveRecord::Relation right_rel) -> ActiveRecord::Relation
|
|
41
|
+
|
|
42
|
+
# @rbs rel: untyped
|
|
43
|
+
# @rbs return: bool
|
|
44
|
+
def is_relation?: (untyped rel) -> bool
|
|
45
|
+
|
|
46
|
+
# @rbs lr: untyped
|
|
47
|
+
# @rbs rr: untyped
|
|
48
|
+
# @rbs return: bool
|
|
49
|
+
def both_relations?: (untyped lr, untyped rr) -> bool
|
|
50
|
+
|
|
51
|
+
# @rbs lr: untyped
|
|
52
|
+
# @rbs rr: untyped
|
|
53
|
+
# @rbs return: bool
|
|
54
|
+
def left_relation_right_enumerable?: (untyped lr, untyped rr) -> bool
|
|
55
|
+
|
|
56
|
+
# @rbs lr: untyped
|
|
57
|
+
# @rbs rr: untyped
|
|
58
|
+
# @rbs return: bool
|
|
59
|
+
def left_enumerable_right_relation?: (untyped lr, untyped rr) -> bool
|
|
60
|
+
end
|
|
61
|
+
end
|
|
@@ -1,68 +1,39 @@
|
|
|
1
1
|
# Generated from lib/quo/composed_query.rb with RBS::Inline
|
|
2
2
|
|
|
3
3
|
module Quo
|
|
4
|
+
# Mixin for queries composed of two child queries
|
|
4
5
|
module ComposedQuery
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
# @rbs left_query_class: singleton(Quo::Query | ::ActiveRecord::Relation)
|
|
11
|
-
# @rbs right_query_class: singleton(Quo::Query | ::ActiveRecord::Relation)
|
|
12
|
-
# @rbs joins: untyped
|
|
13
|
-
# @rbs return: singleton(Quo::ComposedQuery)
|
|
14
|
-
def self?.composer: (untyped chosen_superclass, untyped left_query_class, untyped right_query_class, ?joins: untyped) -> singleton(Quo::ComposedQuery)
|
|
15
|
-
|
|
16
|
-
# We can also merge instance of prepared queries
|
|
17
|
-
# @rbs left_instance: Quo::Query | ::ActiveRecord::Relation
|
|
18
|
-
# @rbs right_instance: Quo::Query | ::ActiveRecord::Relation
|
|
19
|
-
# @rbs joins: untyped
|
|
20
|
-
# @rbs return: Quo::ComposedQuery
|
|
21
|
-
def self?.merge_instances: (Quo::Query | ::ActiveRecord::Relation left_instance, Quo::Query | ::ActiveRecord::Relation right_instance, ?joins: untyped) -> Quo::ComposedQuery
|
|
6
|
+
# Class-level methods shared by every composed query class. Defined once
|
|
7
|
+
# here and extended onto each anon class via the `included` hook below
|
|
8
|
+
# rather than being re-defined on every Class.new in the composer.
|
|
9
|
+
module ClassMethods
|
|
10
|
+
attr_reader _composing_joins: untyped
|
|
22
11
|
|
|
23
|
-
|
|
24
|
-
def query: ...
|
|
12
|
+
attr_reader _left_specification: untyped
|
|
25
13
|
|
|
26
|
-
|
|
27
|
-
def inspect: ...
|
|
14
|
+
attr_reader _right_specification: untyped
|
|
28
15
|
|
|
29
|
-
|
|
30
|
-
# @rbs right_query_class: singleton(Quo::Query | ::ActiveRecord::Relation)
|
|
31
|
-
private def self.validate_query_classes: (untyped left_query_class, untyped right_query_class) -> untyped
|
|
16
|
+
attr_reader _left_query: untyped
|
|
32
17
|
|
|
33
|
-
|
|
34
|
-
# @rbs right_query_class: singleton(Quo::Query | ::ActiveRecord::Relation)
|
|
35
|
-
private def self.collect_properties: (untyped left_query_class, untyped right_query_class) -> untyped
|
|
18
|
+
attr_reader _right_query: untyped
|
|
36
19
|
|
|
37
|
-
|
|
20
|
+
# @rbs return: String
|
|
21
|
+
def inspect: () -> String
|
|
38
22
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
private def self.assign_query_metadata: (Class klass, untyped left_query_class, untyped right_query_class, untyped joins) -> untyped
|
|
23
|
+
# @rbs operand: Class
|
|
24
|
+
# @rbs return: String
|
|
25
|
+
def quo_operand_desc: (Class operand) -> String
|
|
26
|
+
end
|
|
44
27
|
|
|
45
|
-
# @rbs
|
|
46
|
-
# @rbs
|
|
47
|
-
|
|
28
|
+
# @rbs base: Class
|
|
29
|
+
# @rbs return: void
|
|
30
|
+
def self.included: (Class base) -> void
|
|
48
31
|
|
|
49
|
-
# @rbs
|
|
50
|
-
|
|
51
|
-
# @rbs joins: untyped
|
|
52
|
-
private def self.merge_query_and_relation: (Quo::Query query, ::ActiveRecord::Relation relation, untyped joins) -> untyped
|
|
53
|
-
|
|
54
|
-
# @rbs relation: ::ActiveRecord::Relation
|
|
55
|
-
# @rbs query: Quo::Query
|
|
56
|
-
# @rbs joins: untyped
|
|
57
|
-
private def self.merge_relation_and_query: (::ActiveRecord::Relation relation, Quo::Query query, untyped joins) -> untyped
|
|
58
|
-
|
|
59
|
-
# @rbs left_query: Quo::Query | ::ActiveRecord::Relation
|
|
60
|
-
# @rbs right_query: Quo::Query | ::ActiveRecord::Relation
|
|
61
|
-
private def self.merge_query_instances: (Quo::Query | ::ActiveRecord::Relation left_query, Quo::Query | ::ActiveRecord::Relation right_query, untyped joins) -> untyped
|
|
32
|
+
# @rbs override
|
|
33
|
+
def query: ...
|
|
62
34
|
|
|
63
|
-
# @rbs
|
|
64
|
-
|
|
65
|
-
private def self.determine_base_class_for_queries: (Quo::Query | ::ActiveRecord::Relation left_query, Quo::Query | ::ActiveRecord::Relation right_query) -> untyped
|
|
35
|
+
# @rbs override
|
|
36
|
+
def inspect: ...
|
|
66
37
|
|
|
67
38
|
private
|
|
68
39
|
|
|
@@ -86,10 +57,6 @@ module Quo
|
|
|
86
57
|
# @rbs return: ActiveRecord::Relation
|
|
87
58
|
def merge_active_record_relations: (ActiveRecord::Relation left_rel, ActiveRecord::Relation right_rel) -> ActiveRecord::Relation
|
|
88
59
|
|
|
89
|
-
# @rbs left_rel: ActiveRecord::Relation
|
|
90
|
-
# @rbs return: ActiveRecord::Relation
|
|
91
|
-
def apply_joins: (ActiveRecord::Relation left_rel) -> ActiveRecord::Relation
|
|
92
|
-
|
|
93
60
|
# @rbs rel: untyped
|
|
94
61
|
# @rbs return: bool
|
|
95
62
|
def is_relation?: (untyped rel) -> bool
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Generated from lib/quo/composed_relation_backed_query.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
module Quo
|
|
4
|
+
class ComposedRelationBackedQuery
|
|
5
|
+
include ComposedInstance
|
|
6
|
+
|
|
7
|
+
@left: Quo::Query | ActiveRecord::Relation | Enumerable[untyped]
|
|
8
|
+
|
|
9
|
+
@right: Quo::Query | ActiveRecord::Relation | Enumerable[untyped]
|
|
10
|
+
|
|
11
|
+
@merge_joins: Symbol | Hash[untyped, untyped] | Array[untyped] | nil
|
|
12
|
+
|
|
13
|
+
# @rbs override
|
|
14
|
+
def query: ...
|
|
15
|
+
|
|
16
|
+
# @rbs override
|
|
17
|
+
def inspect: ...
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
# @rbs operand: untyped
|
|
22
|
+
# @rbs return: String
|
|
23
|
+
def operand_desc: (untyped operand) -> String
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Generated from lib/quo/composing/base_strategy.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
module Quo
|
|
4
|
+
module Composing
|
|
5
|
+
# Base class for all composition strategies
|
|
6
|
+
class BaseStrategy
|
|
7
|
+
# @rbs left: untyped
|
|
8
|
+
# @rbs right: untyped
|
|
9
|
+
# @rbs return: bool
|
|
10
|
+
def applicable?: (untyped left, untyped right) -> bool
|
|
11
|
+
|
|
12
|
+
# @rbs return: untyped
|
|
13
|
+
def compose: () -> untyped
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Generated from lib/quo/composing/class_strategy.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
module Quo
|
|
4
|
+
module Composing
|
|
5
|
+
# Base class for class composition strategies
|
|
6
|
+
class ClassStrategy < BaseStrategy
|
|
7
|
+
# @rbs left_query_class: Class
|
|
8
|
+
# @rbs right_query_class: Class
|
|
9
|
+
# @rbs return: void
|
|
10
|
+
def validate_query_classes: (Class left_query_class, Class right_query_class) -> void
|
|
11
|
+
|
|
12
|
+
# Collect properties that need to be (re)defined on the composed class.
|
|
13
|
+
# Properties already declared on `chosen_superclass` are inherited via the
|
|
14
|
+
# normal Ruby/Literal class hierarchy and do not need to be re-registered;
|
|
15
|
+
# skipping them avoids the per-prop Literal::Property allocation, schema
|
|
16
|
+
# dup, and `module_eval` of reader/writer source on every Class.new.
|
|
17
|
+
# @rbs chosen_superclass: Class
|
|
18
|
+
# @rbs left_query_class: Class
|
|
19
|
+
# @rbs right_query_class: Class
|
|
20
|
+
# @rbs return: Hash[Symbol, Literal::Property]
|
|
21
|
+
def collect_properties: (Class chosen_superclass, Class left_query_class, Class right_query_class) -> Hash[Symbol, Literal::Property]
|
|
22
|
+
|
|
23
|
+
# @rbs chosen_superclass: Class
|
|
24
|
+
# @rbs props: Hash[Symbol, Literal::Property]
|
|
25
|
+
# @rbs return: Class & Quo::ComposedQuery
|
|
26
|
+
def create_composed_class: (Class chosen_superclass, Hash[Symbol, Literal::Property] props) -> (Class & Quo::ComposedQuery)
|
|
27
|
+
|
|
28
|
+
# @rbs klass: Class
|
|
29
|
+
# @rbs left_query_class: Class
|
|
30
|
+
# @rbs right_query_class: Class
|
|
31
|
+
# @rbs joins: Symbol | Hash[Symbol, untyped] | Array[Symbol | Hash[Symbol, untyped]]?
|
|
32
|
+
# @rbs left_spec: Quo::RelationBackedQuerySpecification?
|
|
33
|
+
# @rbs right_spec: Quo::RelationBackedQuerySpecification?
|
|
34
|
+
# @rbs return: void
|
|
35
|
+
def assign_query_metadata: (Class klass, Class left_query_class, Class right_query_class, Symbol | Hash[Symbol, untyped] | Array[Symbol | Hash[Symbol, untyped]]? joins, Quo::RelationBackedQuerySpecification? left_spec, Quo::RelationBackedQuerySpecification? right_spec) -> void
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Generated from lib/quo/composing/class_strategy_registry.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
module Quo
|
|
4
|
+
module Composing
|
|
5
|
+
# Registry for class composition strategies
|
|
6
|
+
class ClassStrategyRegistry
|
|
7
|
+
# @rbs return: Array[Quo::Composing::BaseStrategy]
|
|
8
|
+
def strategies: () -> Array[Quo::Composing::BaseStrategy]
|
|
9
|
+
|
|
10
|
+
# @rbs left: Class
|
|
11
|
+
# @rbs right: Class
|
|
12
|
+
# @rbs return: Quo::Composing::BaseStrategy
|
|
13
|
+
def find_strategy: (Class left, Class right) -> Quo::Composing::BaseStrategy
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Generated from lib/quo/composing/query_classes_strategy.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
module Quo
|
|
4
|
+
module Composing
|
|
5
|
+
# Strategy for composing two Query classes
|
|
6
|
+
class QueryClassesStrategy < ClassStrategy
|
|
7
|
+
# @rbs override
|
|
8
|
+
# @rbs left: Class
|
|
9
|
+
# @rbs right: Class
|
|
10
|
+
# @rbs return: bool
|
|
11
|
+
def applicable?: ...
|
|
12
|
+
|
|
13
|
+
# @rbs override
|
|
14
|
+
# @rbs chosen_superclass: Class
|
|
15
|
+
# @rbs left_query_class: Class
|
|
16
|
+
# @rbs right_query_class: Class
|
|
17
|
+
# @rbs joins: Symbol | Hash[Symbol, untyped] | Array[Symbol | Hash[Symbol, untyped]]?
|
|
18
|
+
# @rbs left_spec: Quo::RelationBackedQuerySpecification?
|
|
19
|
+
# @rbs right_spec: Quo::RelationBackedQuerySpecification?
|
|
20
|
+
# @rbs return: Class & Quo::ComposedQuery
|
|
21
|
+
def compose: ...
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Generated from lib/quo/composing.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
module Quo
|
|
4
|
+
module Composing
|
|
5
|
+
CLASS_STRATEGY_REGISTRY: untyped
|
|
6
|
+
|
|
7
|
+
# @rbs chosen_superclass: Class
|
|
8
|
+
# @rbs left_query_class: Class
|
|
9
|
+
# @rbs right_query_class: Class
|
|
10
|
+
# @rbs joins: Symbol | Hash[Symbol, untyped] | Array[Symbol | Hash[Symbol, untyped]]?
|
|
11
|
+
# @rbs left_spec: Quo::RelationBackedQuerySpecification?
|
|
12
|
+
# @rbs right_spec: Quo::RelationBackedQuerySpecification?
|
|
13
|
+
# @rbs return: Class & Quo::ComposedQuery
|
|
14
|
+
def self.composer: (Class chosen_superclass, Class left_query_class, Class right_query_class, ?joins: Symbol | Hash[Symbol, untyped] | Array[Symbol | Hash[Symbol, untyped]]?, ?left_spec: Quo::RelationBackedQuerySpecification?, ?right_spec: Quo::RelationBackedQuerySpecification?) -> (Class & Quo::ComposedQuery)
|
|
15
|
+
|
|
16
|
+
# @rbs left_instance: Quo::Query
|
|
17
|
+
# @rbs right_instance: Quo::Query | ActiveRecord::Relation | Object & Enumerable[untyped]
|
|
18
|
+
# @rbs joins: Symbol | Hash[Symbol, untyped] | Array[Symbol | Hash[Symbol, untyped]]?
|
|
19
|
+
# @rbs return: Quo::Query
|
|
20
|
+
def self.merge_instances: (Quo::Query left_instance, Quo::Query | ActiveRecord::Relation | Object & Enumerable[untyped] right_instance, ?joins: Symbol | Hash[Symbol, untyped] | Array[Symbol | Hash[Symbol, untyped]]?) -> Quo::Query
|
|
21
|
+
|
|
22
|
+
# @rbs operand: untyped
|
|
23
|
+
# @rbs return: bool
|
|
24
|
+
private def self.relation_backed?: (untyped operand) -> bool
|
|
25
|
+
|
|
26
|
+
# @rbs left: untyped
|
|
27
|
+
# @rbs right: untyped
|
|
28
|
+
# @rbs return: Array[Integer?]
|
|
29
|
+
private def self.inherited_pagination: (untyped left, untyped right) -> Array[Integer?]
|
|
30
|
+
|
|
31
|
+
# @rbs operand: untyped
|
|
32
|
+
# @rbs return: untyped
|
|
33
|
+
private def self.pagination_source: (untyped operand) -> untyped
|
|
34
|
+
|
|
35
|
+
# @rbs left: untyped
|
|
36
|
+
# @rbs right: untyped
|
|
37
|
+
# @rbs return: Proc?
|
|
38
|
+
private def self.inherited_transformer: (untyped left, untyped right) -> Proc?
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Generated from lib/quo/minitest/helpers.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
module Quo
|
|
4
|
+
module Minitest
|
|
5
|
+
# Test helpers for stubbing query objects in Minitest
|
|
6
|
+
module Helpers
|
|
7
|
+
include Quo::Testing::FakeHelpers
|
|
8
|
+
|
|
9
|
+
def fake_query: (untyped query_class, ?results: untyped, ?total_count: untyped, ?page_count: untyped) ?{ (?) -> untyped } -> untyped
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|