quo 0.6.0 → 1.0.0.alpha1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/.standard.yml +4 -1
  3. data/Appraisals +11 -0
  4. data/CHANGELOG.md +78 -0
  5. data/Gemfile +6 -4
  6. data/LICENSE.txt +1 -1
  7. data/README.md +37 -36
  8. data/Steepfile +0 -2
  9. data/gemfiles/rails_7.0.gemfile +15 -0
  10. data/gemfiles/rails_7.1.gemfile +15 -0
  11. data/gemfiles/rails_7.2.gemfile +15 -0
  12. data/lib/quo/collection_backed_query.rb +87 -0
  13. data/lib/quo/collection_results.rb +44 -0
  14. data/lib/quo/composed_query.rb +168 -0
  15. data/lib/quo/engine.rb +11 -0
  16. data/lib/quo/minitest/helpers.rb +41 -0
  17. data/lib/quo/preloadable.rb +46 -0
  18. data/lib/quo/query.rb +97 -214
  19. data/lib/quo/relation_backed_query.rb +177 -0
  20. data/lib/quo/relation_results.rb +58 -0
  21. data/lib/quo/results.rb +48 -44
  22. data/lib/quo/rspec/helpers.rb +31 -9
  23. data/lib/quo/testing/collection_backed_fake.rb +29 -0
  24. data/lib/quo/testing/relation_backed_fake.rb +52 -0
  25. data/lib/quo/version.rb +3 -1
  26. data/lib/quo.rb +22 -30
  27. data/rbs_collection.yaml +0 -2
  28. data/sig/generated/quo/collection_backed_query.rbs +39 -0
  29. data/sig/generated/quo/collection_results.rbs +30 -0
  30. data/sig/generated/quo/composed_query.rbs +83 -0
  31. data/sig/generated/quo/engine.rbs +6 -0
  32. data/sig/generated/quo/preloadable.rbs +29 -0
  33. data/sig/generated/quo/query.rbs +98 -0
  34. data/sig/generated/quo/relation_backed_query.rbs +90 -0
  35. data/sig/generated/quo/relation_results.rbs +38 -0
  36. data/sig/generated/quo/results.rbs +39 -0
  37. data/sig/generated/quo/version.rbs +5 -0
  38. data/sig/generated/quo.rbs +9 -0
  39. metadata +67 -30
  40. data/lib/quo/eager_query.rb +0 -51
  41. data/lib/quo/loaded_query.rb +0 -18
  42. data/lib/quo/merged_query.rb +0 -36
  43. data/lib/quo/query_composer.rb +0 -78
  44. data/lib/quo/railtie.rb +0 -7
  45. data/lib/quo/utilities/callstack.rb +0 -21
  46. data/lib/quo/utilities/compose.rb +0 -18
  47. data/lib/quo/utilities/sanitize.rb +0 -19
  48. data/lib/quo/utilities/wrap.rb +0 -23
  49. data/lib/quo/wrapped_query.rb +0 -18
  50. data/sig/quo/eager_query.rbs +0 -15
  51. data/sig/quo/loaded_query.rbs +0 -7
  52. data/sig/quo/merged_query.rbs +0 -19
  53. data/sig/quo/query.rbs +0 -83
  54. data/sig/quo/query_composer.rbs +0 -32
  55. data/sig/quo/results.rbs +0 -22
  56. data/sig/quo/utilities/callstack.rbs +0 -7
  57. data/sig/quo/utilities/compose.rbs +0 -8
  58. data/sig/quo/utilities/sanitize.rbs +0 -9
  59. data/sig/quo/utilities/wrap.rbs +0 -11
  60. data/sig/quo/wrapped_query.rbs +0 -11
  61. data/sig/quo.rbs +0 -41
@@ -0,0 +1,177 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rbs_inline: enabled
4
+
5
+ require "literal"
6
+
7
+ module Quo
8
+ class RelationBackedQuery < Query
9
+ # @rbs query: ActiveRecord::Relation | Quo::Query
10
+ # @rbs props: Hash[Symbol, untyped]
11
+ # @rbs &block: () -> ActiveRecord::Relation | Quo::Query | Object & Enumerable[untyped]
12
+ # @rbs return: Quo::RelationBackedQuery
13
+ def self.wrap(query = nil, props: {}, &block)
14
+ raise ArgumentError, "either a query or a block must be provided" unless query || block
15
+
16
+ klass = Class.new(self) do
17
+ props.each do |name, property|
18
+ if property.is_a?(Literal::Property)
19
+ prop name, property.type, property.kind, reader: property.reader, writer: property.writer, default: property.default
20
+ else
21
+ prop name, property
22
+ end
23
+ end
24
+ end
25
+ if block
26
+ klass.define_method(:query, &block)
27
+ else
28
+ klass.define_method(:query) { query }
29
+ end
30
+ klass
31
+ end
32
+
33
+ # @rbs conditions: untyped?
34
+ # @rbs return: String
35
+ def self.sanitize_sql_for_conditions(conditions)
36
+ ActiveRecord::Base.sanitize_sql_for_conditions(conditions)
37
+ end
38
+
39
+ # @rbs string: String
40
+ # @rbs return: String
41
+ def self.sanitize_sql_string(string)
42
+ sanitize_sql_for_conditions(["'%s'", string])
43
+ end
44
+
45
+ # @rbs value: untyped
46
+ # @rbs return: String
47
+ def self.sanitize_sql_parameter(value)
48
+ sanitize_sql_for_conditions(["?", value])
49
+ end
50
+
51
+ # These store options related to building the underlying query, we don't want to expose these as public properties
52
+ # @rbs!
53
+ # @_rel_group: untyped?
54
+ # @_rel_distinct: bool?
55
+ # @_rel_order: untyped?
56
+ # @_rel_limit: untyped?
57
+ # @_rel_preload: untyped?
58
+ # @_rel_includes: untyped?
59
+ # @_rel_select: untyped?
60
+ prop :_rel_group, _Nilable(_Any), reader: false, writer: false
61
+ prop :_rel_distinct, _Nilable(_Boolean), reader: false, writer: false
62
+ prop :_rel_order, _Nilable(_Any), reader: false, writer: false
63
+ prop :_rel_limit, _Nilable(_Any), reader: false, writer: false
64
+ prop :_rel_preload, _Nilable(_Any), reader: false, writer: false
65
+ prop :_rel_includes, _Nilable(_Any), reader: false, writer: false
66
+ prop :_rel_select, _Nilable(_Any), reader: false, writer: false
67
+
68
+ # Methods to prepare the query
69
+
70
+ # SQL 'SELECT' configuration, calls to underlying AR relation
71
+ # @rbs *options: untyped
72
+ # @rbs return: Quo::Query
73
+ def select(*options)
74
+ copy(_rel_select: options)
75
+ end
76
+
77
+ # SQL 'LIMIT' configuration, calls to underlying AR relation
78
+ # @rbs limit: untyped
79
+ # @rbs return: Quo::Query
80
+ def limit(limit)
81
+ copy(_rel_limit: limit)
82
+ end
83
+
84
+ # SQL 'ORDER BY' configuration, calls to underlying AR relation
85
+ # @rbs options: untyped
86
+ # @rbs return: Quo::Query
87
+ def order(options)
88
+ copy(_rel_order: options)
89
+ end
90
+
91
+ # SQL 'GROUP BY' configuration, calls to underlying AR relation
92
+ # @rbs *options: untyped
93
+ # @rbs return: Quo::Query
94
+ def group(*options)
95
+ copy(_rel_group: options)
96
+ end
97
+
98
+ # Configures underlying AR relation to include associations
99
+ # @rbs *options: untyped
100
+ # @rbs return: Quo::Query
101
+ def includes(*options)
102
+ copy(_rel_includes: options)
103
+ end
104
+
105
+ # Configures underlying AR relation to preload associations
106
+ # @rbs *options: untyped
107
+ # @rbs return: Quo::Query
108
+ def preload(*options)
109
+ copy(_rel_preload: options)
110
+ end
111
+
112
+ # Calls to underlying AR distinct method
113
+ # @rbs enabled: bool
114
+ # @rbs return: Quo::Query
115
+ def distinct(enabled = true)
116
+ copy(_rel_distinct: enabled)
117
+ end
118
+
119
+ # Should these also be exposed? whats the point of exposing AR relation directly?
120
+ def eager_load
121
+ end
122
+
123
+ def joins
124
+ end
125
+
126
+ def left_outer_joins
127
+ end
128
+
129
+ # Delegate methods that let us get the model class (available on AR relations)
130
+ # @rbs def model: () -> (untyped | nil)
131
+ # @rbs def klass: () -> (untyped | nil)
132
+ delegate :model, :klass, to: :underlying_query
133
+
134
+ # @rbs return: Quo::CollectionBackedQuery
135
+ def to_collection(total_count: nil)
136
+ Quo.collection_backed_query_base_class.wrap(results.to_a).new(total_count:)
137
+ end
138
+
139
+ def results #: Quo::Results
140
+ Quo::RelationResults.new(self, transformer: transformer)
141
+ end
142
+
143
+ # Return the SQL string for this query if its a relation type query object
144
+ def to_sql #: String
145
+ configured_query.to_sql if relation?
146
+ end
147
+
148
+ private
149
+
150
+ def validated_query
151
+ query.tap do |q|
152
+ raise ArgumentError, "#query must return an ActiveRecord Relation or a Quo::Query instance" unless query.nil? || q.is_a?(::ActiveRecord::Relation) || q.is_a?(Quo::Query)
153
+ end
154
+ end
155
+
156
+ # The underlying query is essentially the configured query with optional extras setup
157
+ def underlying_query #: ActiveRecord::Relation
158
+ rel = quo_unwrap_unpaginated_query(validated_query)
159
+
160
+ rel = rel.group(@_rel_group) if @_rel_group.present?
161
+ rel = rel.distinct if @_rel_distinct
162
+ rel = rel.order(@_rel_order) if @_rel_order.present?
163
+ rel = rel.limit(@_rel_limit) if @_rel_limit.present?
164
+ rel = rel.preload(@_rel_preload) if @_rel_preload.present?
165
+ rel = rel.includes(@_rel_includes) if @_rel_includes.present?
166
+ @_rel_select.present? ? rel.select(@_rel_select) : rel
167
+ end
168
+
169
+ # The configured query is the underlying query with paging
170
+ def configured_query #: ActiveRecord::Relation
171
+ q = underlying_query
172
+ return q unless paged?
173
+
174
+ q.offset(offset).limit(sanitised_page_size)
175
+ end
176
+ end
177
+ end
@@ -0,0 +1,58 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rbs_inline: enabled
4
+
5
+ module Quo
6
+ class RelationResults < Results
7
+ # @rbs query: Quo::Query
8
+ # @rbs transformer: (^(untyped, ?Integer) -> untyped)?
9
+ # @rbs return: void
10
+ def initialize(query, transformer: nil)
11
+ raise ArgumentError, "Query must be a RelationBackedQuery" unless query.is_a?(Quo::RelationBackedQuery)
12
+ @query = query
13
+ @configured_query = query.unwrap
14
+ @transformer = transformer
15
+ end
16
+
17
+ # Are there any results for this query?
18
+ def exists? #: bool
19
+ return @configured_query.exists? if @query.relation?
20
+ @configured_query.present?
21
+ end
22
+
23
+ # Gets the count of all results ignoring the current page and page size (if set).
24
+ def total_count #: Integer
25
+ count_query(@query.unwrap_unpaginated)
26
+ end
27
+
28
+ # Gets the actual count of elements in the page of results (assuming paging is being used, otherwise the count of
29
+ # all results)
30
+ def page_count #: Integer
31
+ count_query(@configured_query)
32
+ end
33
+
34
+ private
35
+
36
+ # @rbs @query: Quo::RelationBackedQuery
37
+ # @rbs @configured_query: ActiveRecord::Relation
38
+
39
+ # Note we reselect the query as this prevents query errors if the SELECT clause is not compatible with COUNT
40
+ # (SQLException: wrong number of arguments to function COUNT()). We do this in two ways, either with the primary key
41
+ # or with Arel.star. The primary key is the most compatible way to count, but if the query does not have a primary
42
+ # we fallback. The fallback "*" wont work in certain situations though, specifically if we have a limit() on the query
43
+ # which Arel constructs as a subquery. In this case we will get a SQL error as the generated SQL contains
44
+ # `SELECT COUNT(count_column) FROM (SELECT * AS count_column FROM ...) subquery_for_count` where the error is:
45
+ # `ActiveRecord::StatementInvalid: SQLite3::SQLException: near "AS": syntax error`
46
+ # Either way DB engines know how to count efficiently.
47
+ # @rbs query: ActiveRecord::Relation
48
+ # @rbs return: Integer
49
+ def count_query(query)
50
+ pk = query.model.primary_key
51
+ if pk
52
+ query.reselect(pk).count
53
+ else
54
+ query.reselect(Arel.star).count
55
+ end
56
+ end
57
+ end
58
+ end
data/lib/quo/results.rb CHANGED
@@ -1,85 +1,89 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "forwardable"
4
- require_relative "./utilities/callstack"
3
+ # rbs_inline: enabled
5
4
 
6
5
  module Quo
7
6
  class Results
8
- extend Forwardable
9
- include Quo::Utilities::Callstack
7
+ def empty? #: bool
8
+ !exists?
9
+ end
10
10
 
11
- def initialize(query, transformer: nil)
12
- @query = query
13
- @unwrapped = query.unwrap
14
- @transformer = transformer
11
+ # Alias for total_count
12
+ def count #: Integer
13
+ total_count
15
14
  end
16
15
 
17
- def_delegators :unwrapped,
18
- :include?,
19
- :member?,
20
- :all?,
21
- :any?,
22
- :none?,
23
- :one?,
24
- :count
16
+ # Alias for total_count
17
+ def size #: Integer
18
+ total_count
19
+ end
25
20
 
21
+ # Alias for page_count
22
+ def page_size #: Integer
23
+ page_count
24
+ end
25
+
26
+ # @rbs &block: (untyped, *untyped) -> untyped
27
+ # @rbs return: Hash[untyped, Array[untyped]]
26
28
  def group_by(&block)
27
- debug_callstack
28
- grouped = unwrapped.group_by do |*block_args|
29
+ grouped = @configured_query.group_by do |*block_args|
29
30
  x = block_args.first
30
- transformed = transformer ? transformer.call(x) : x
31
+ transformed = transform? ? @transformer.call(x) : x
31
32
  block ? block.call(transformed, *(block_args[1..] || [])) : transformed
32
33
  end
33
34
 
34
35
  grouped.tap do |groups|
35
36
  groups.transform_values! do |values|
36
- transformer ? values.map { |x| transformer.call(x) } : values
37
+ @transformer ? values.map { |x| @transformer.call(x) } : values
37
38
  end
38
39
  end
39
40
  end
40
41
 
41
42
  # Delegate other enumerable methods to underlying collection but also transform
43
+ # @rbs override
42
44
  def method_missing(method, *args, **kwargs, &block)
43
- if unwrapped.respond_to?(method)
44
- debug_callstack
45
- if block
46
- unwrapped.send(method, *args, **kwargs) do |*block_args|
47
- x = block_args.first
48
- transformed = transformer ? transformer.call(x) : x
49
- other_args = block_args[1..] || []
50
- block.call(transformed, *other_args)
51
- end
52
- else
53
- raw = unwrapped.send(method, *args, **kwargs)
54
- # FIXME: consider how to handle applying a transformer to a Enumerator...
55
- return raw if raw.is_a?(Quo::Results) || raw.is_a?(::Enumerator)
56
- transform_results(raw)
45
+ return super unless respond_to_missing?(method)
46
+
47
+ if block
48
+ @configured_query.send(method, *args, **kwargs) do |*block_args|
49
+ x = block_args.first
50
+ transformed = transform? ? @transformer.call(x) : x
51
+ other_args = block_args[1..] || []
52
+ block.call(transformed, *other_args)
57
53
  end
58
54
  else
59
- super
55
+ raw = @configured_query.send(method, *args, **kwargs)
56
+ # FIXME: consider how to handle applying a transformer to a Enumerator...
57
+ return raw if raw.is_a?(Quo::RelationResults) || raw.is_a?(::Enumerator)
58
+ transform_results(raw)
60
59
  end
61
60
  end
62
61
 
62
+ # @rbs name: Symbol
63
+ # @rbs include_private: bool
64
+ # @rbs return: bool
63
65
  def respond_to_missing?(name, include_private = false)
64
- enumerable_methods_supported.include?(name)
66
+ @configured_query.respond_to?(name, include_private)
67
+ end
68
+
69
+ def transform? #: bool
70
+ @transformer.present?
65
71
  end
66
72
 
67
73
  private
68
74
 
69
- attr_reader :transformer, :unwrapped
75
+ # @rbs @transformer: (^(untyped, ?Integer) -> untyped)?
70
76
 
77
+ # @rbs results: untyped
78
+ # @rbs return: untyped
71
79
  def transform_results(results)
72
- return results unless transformer
80
+ return results unless transform?
73
81
 
74
82
  if results.is_a?(Enumerable)
75
- results.map.with_index { |item, i| transformer.call(item, i) }
83
+ results.map.with_index { |item, i| @transformer.call(item, i) }
76
84
  else
77
- transformer.call(results)
85
+ @transformer.call(results)
78
86
  end
79
87
  end
80
-
81
- def enumerable_methods_supported
82
- [:find_each] + Enumerable.instance_methods
83
- end
84
88
  end
85
89
  end
@@ -1,18 +1,40 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative "../testing/collection_backed_fake"
4
+ require_relative "../testing/relation_backed_fake"
5
+
3
6
  module Quo
4
7
  module Rspec
5
8
  module Helpers
6
- def stub_query(query_class, options = {})
7
- results = options.fetch(:results, [])
8
- with = options[:with]
9
- unless with.nil?
10
- return(
11
- allow(query_class).to receive(:new)
12
- .with(with) { ::Quo::LoadedQuery.new(results) }
13
- )
9
+ def fake_query(query_class, with: nil, results: [], total_count: nil, page_count: nil, &block)
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
16
+
17
+ def query
18
+ collection
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
36
+ raise ArgumentError, "Not a Query class: #{query_class}"
14
37
  end
15
- allow(query_class).to receive(:new) { ::Quo::LoadedQuery.new(results) }
16
38
  end
17
39
  end
18
40
  end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rbs_inline: enabled
4
+
5
+ module Quo
6
+ module Testing
7
+ class CollectionBackedFake < Quo.collection_backed_query_base_class
8
+ prop :results, _Any, reader: false
9
+ prop :page_count, _Nilable(Integer), reader: false
10
+
11
+ def collection
12
+ @results
13
+ end
14
+
15
+ def results
16
+ klass = Class.new(CollectionResults) do
17
+ def page_count
18
+ @query.page_count
19
+ end
20
+ end
21
+ klass.new(self)
22
+ end
23
+
24
+ def page_count
25
+ @page_count || validated_query.size
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,52 @@
1
+ # frozen_string_literal: true
2
+
3
+ # rbs_inline: enabled
4
+
5
+ module Quo
6
+ module Testing
7
+ class RelationBackedFake < Quo.relation_backed_query_base_class
8
+ prop :results, _Any, reader: false
9
+ prop :page_count, _Nilable(Integer), reader: false
10
+ prop :total_count, _Nilable(Integer), reader: false
11
+
12
+ def query
13
+ @results
14
+ end
15
+
16
+ def results
17
+ klass = Class.new(RelationResults) do
18
+ def page_count
19
+ @query.page_count
20
+ end
21
+
22
+ def total_count
23
+ @query.total_count
24
+ end
25
+ end
26
+ klass.new(self)
27
+ end
28
+
29
+ def page_count
30
+ @page_count || validated_query.size
31
+ end
32
+
33
+ def total_count
34
+ @total_count || validated_query.size
35
+ end
36
+
37
+ private
38
+
39
+ def validated_query
40
+ query
41
+ end
42
+
43
+ def underlying_query
44
+ validated_query
45
+ end
46
+
47
+ def configured_query
48
+ validated_query
49
+ end
50
+ end
51
+ end
52
+ end
data/lib/quo/version.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # rbs_inline: enabled
4
+
3
5
  module Quo
4
- VERSION = "0.6.0"
6
+ VERSION = "1.0.0.alpha1"
5
7
  end
data/lib/quo.rb CHANGED
@@ -1,40 +1,32 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # rbs_inline: enabled
4
+
3
5
  require_relative "quo/version"
4
- require_relative "quo/railtie" if defined?(Rails)
5
- require_relative "quo/query"
6
- require_relative "quo/eager_query"
7
- require_relative "quo/loaded_query"
8
- require_relative "quo/merged_query"
9
- require_relative "quo/wrapped_query"
10
- require_relative "quo/query_composer"
11
- require_relative "quo/results"
6
+ require "quo/engine"
12
7
 
13
8
  module Quo
14
- class << self
15
- def configuration
16
- @configuration ||= Configuration.new
17
- end
9
+ extend ActiveSupport::Autoload
18
10
 
19
- def configure
20
- yield(configuration) if block_given?
21
- configuration
22
- end
23
- end
11
+ autoload :Query
12
+ autoload :Preloadable
13
+ autoload :RelationBackedQuery
14
+ autoload :Results
15
+ autoload :RelationResults
16
+ autoload :CollectionResults
17
+ autoload :ComposedQuery
18
+ autoload :CollectionBackedQuery
24
19
 
25
- class Configuration
26
- attr_accessor :formatted_query_log,
27
- :query_show_callstack_size,
28
- :logger,
29
- :max_page_size,
30
- :default_page_size
20
+ mattr_accessor :relation_backed_query_base_class, default: "Quo::RelationBackedQuery"
21
+ mattr_accessor :collection_backed_query_base_class, default: "Quo::CollectionBackedQuery"
22
+ mattr_accessor :max_page_size, default: 200
23
+ mattr_accessor :default_page_size, default: 20
24
+
25
+ def self.relation_backed_query_base_class #: Quo::RelationBackedQuery
26
+ @@relation_backed_query_base_class.constantize
27
+ end
31
28
 
32
- def initialize
33
- @formatted_query_log = true
34
- @query_show_callstack_size = 10
35
- @logger = nil
36
- @max_page_size = 200
37
- @default_page_size = 20
38
- end
29
+ def self.collection_backed_query_base_class #: Quo::CollectionBackedQuery
30
+ @@collection_backed_query_base_class.constantize
39
31
  end
40
32
  end
data/rbs_collection.yaml CHANGED
@@ -9,8 +9,6 @@ sources:
9
9
  path: .gem_rbs_collection
10
10
 
11
11
  gems:
12
- - name: quo
13
- ignore: true
14
12
  - name: forwardable
15
13
  # Skip loading rbs gem's RBS.
16
14
  # It's unnecessary if you don't use rbs as a library.
@@ -0,0 +1,39 @@
1
+ # Generated from lib/quo/collection_backed_query.rb with RBS::Inline
2
+
3
+ module Quo
4
+ class CollectionBackedQuery < Query
5
+ # Wrap an enumerable collection or a block that returns an enumerable collection
6
+ # @rbs data: untyped, props: Symbol => untyped, block: () -> untyped
7
+ # @rbs return: Quo::CollectionBackedQuery
8
+ def self.wrap: (?untyped data, ?props: untyped) ?{ (?) -> untyped } -> Quo::CollectionBackedQuery
9
+
10
+ # @rbs return: Object & Enumerable[untyped]
11
+ def collection: () -> (Object & Enumerable[untyped])
12
+
13
+ # The default implementation of `query` just calls `collection`, however you can also
14
+ # override this method to return an ActiveRecord::Relation or any other query-like object as usual in a Query object.
15
+ # @rbs return: Object & Enumerable[untyped]
16
+ def query: () -> (Object & Enumerable[untyped])
17
+
18
+ def results: () -> untyped
19
+
20
+ # @rbs override
21
+ def relation?: ...
22
+
23
+ # @rbs override
24
+ def collection?: ...
25
+
26
+ # @rbs override
27
+ def to_collection: ...
28
+
29
+ private
30
+
31
+ def validated_query: () -> untyped
32
+
33
+ # @rbs return: Object & Enumerable[untyped]
34
+ def underlying_query: () -> (Object & Enumerable[untyped])
35
+
36
+ # The configured query is the underlying query with paging
37
+ def configured_query: () -> (Object & Enumerable[untyped])
38
+ end
39
+ end
@@ -0,0 +1,30 @@
1
+ # Generated from lib/quo/collection_results.rb with RBS::Inline
2
+
3
+ module Quo
4
+ class CollectionResults < Results
5
+ # @rbs override
6
+ def initialize: ...
7
+
8
+ # Are there any results for this query?
9
+ def exists?: () -> bool
10
+
11
+ def empty?: () -> bool
12
+
13
+ # Gets the count of all results ignoring the current page and page size (if set).
14
+ # Optionally return the `total_count` option if it has been set.
15
+ # This is useful when the total count is known and not equal to size
16
+ # of wrapped collection.
17
+ # @rbs override
18
+ def total_count: ...
19
+
20
+ # Gets the actual count of elements in the page of results (assuming paging is being used, otherwise the count of
21
+ # all results)
22
+ def page_count: () -> Integer
23
+
24
+ @query: Quo::CollectionBackedQuery
25
+
26
+ @transformer: (^(untyped, ?Integer) -> untyped)?
27
+
28
+ @configured_query: Object & Enumerable[untyped]
29
+ end
30
+ end