quo 0.5.3 → 1.0.0.alpha1

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.
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 -69
  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 +101 -213
  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 -20
  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.5.3"
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