quo 0.6.0 → 1.0.0.beta1
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/.standard.yml +4 -1
- data/Appraisals +15 -0
- data/CHANGELOG.md +78 -0
- data/Gemfile +6 -4
- data/LICENSE.txt +1 -1
- data/README.md +222 -232
- data/Steepfile +0 -2
- data/gemfiles/rails_7.0.gemfile +15 -0
- data/gemfiles/rails_7.1.gemfile +15 -0
- data/gemfiles/rails_7.2.gemfile +15 -0
- data/gemfiles/rails_8.0.gemfile +15 -0
- data/lib/quo/collection_backed_query.rb +87 -0
- data/lib/quo/collection_results.rb +44 -0
- data/lib/quo/composed_query.rb +278 -0
- data/lib/quo/engine.rb +11 -0
- data/lib/quo/minitest/helpers.rb +41 -0
- data/lib/quo/preloadable.rb +46 -0
- data/lib/quo/query.rb +97 -215
- data/lib/quo/relation_backed_query.rb +150 -0
- data/lib/quo/relation_backed_query_specification.rb +154 -0
- data/lib/quo/relation_results.rb +58 -0
- data/lib/quo/results.rb +48 -44
- data/lib/quo/rspec/helpers.rb +31 -9
- data/lib/quo/testing/collection_backed_fake.rb +29 -0
- data/lib/quo/testing/relation_backed_fake.rb +52 -0
- data/lib/quo/version.rb +3 -1
- data/lib/quo.rb +23 -30
- data/rbs_collection.yaml +0 -2
- data/sig/generated/quo/collection_backed_query.rbs +39 -0
- data/sig/generated/quo/collection_results.rbs +30 -0
- data/sig/generated/quo/composed_query.rbs +112 -0
- data/sig/generated/quo/engine.rbs +6 -0
- data/sig/generated/quo/preloadable.rbs +29 -0
- data/sig/generated/quo/query.rbs +98 -0
- data/sig/generated/quo/relation_backed_query.rbs +67 -0
- data/sig/generated/quo/relation_backed_query_specification.rbs +94 -0
- data/sig/generated/quo/relation_results.rbs +38 -0
- data/sig/generated/quo/results.rbs +39 -0
- data/sig/generated/quo/testing/collection_backed_fake.rbs +13 -0
- data/sig/generated/quo/testing/relation_backed_fake.rbs +23 -0
- data/sig/generated/quo/version.rbs +5 -0
- data/sig/generated/quo.rbs +9 -0
- data/sig/literal.rbs +7 -0
- metadata +77 -37
- data/lib/quo/eager_query.rb +0 -51
- data/lib/quo/loaded_query.rb +0 -18
- data/lib/quo/merged_query.rb +0 -36
- data/lib/quo/query_composer.rb +0 -78
- data/lib/quo/railtie.rb +0 -7
- data/lib/quo/utilities/callstack.rb +0 -21
- data/lib/quo/utilities/compose.rb +0 -18
- data/lib/quo/utilities/sanitize.rb +0 -19
- data/lib/quo/utilities/wrap.rb +0 -23
- data/lib/quo/wrapped_query.rb +0 -18
- data/sig/quo/eager_query.rbs +0 -15
- data/sig/quo/loaded_query.rbs +0 -7
- data/sig/quo/merged_query.rbs +0 -19
- data/sig/quo/query.rbs +0 -83
- data/sig/quo/query_composer.rbs +0 -32
- data/sig/quo/results.rbs +0 -22
- data/sig/quo/utilities/callstack.rbs +0 -7
- data/sig/quo/utilities/compose.rbs +0 -8
- data/sig/quo/utilities/sanitize.rbs +0 -9
- data/sig/quo/utilities/wrap.rbs +0 -11
- data/sig/quo/wrapped_query.rbs +0 -11
- data/sig/quo.rbs +0 -41
@@ -0,0 +1,154 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# rbs_inline: enabled
|
4
|
+
|
5
|
+
module Quo
|
6
|
+
# RelationBackedQuerySpecification encapsulates all the options for building a SQL query
|
7
|
+
# This separates the storage of query options from the actual query construction
|
8
|
+
# and provides a cleaner interface for RelationBackedQuery
|
9
|
+
class RelationBackedQuerySpecification
|
10
|
+
# @rbs!
|
11
|
+
# @options: Hash[Symbol, untyped]
|
12
|
+
attr_reader :options
|
13
|
+
|
14
|
+
# @rbs options: Hash[Symbol, untyped]
|
15
|
+
def initialize(options = {})
|
16
|
+
@options = options
|
17
|
+
end
|
18
|
+
|
19
|
+
# Creates a new specification with merged options
|
20
|
+
# @rbs new_options: Hash[Symbol, untyped]
|
21
|
+
# @rbs return: Quo::QuerySpecification
|
22
|
+
def merge(new_options)
|
23
|
+
self.class.new(options.merge(new_options))
|
24
|
+
end
|
25
|
+
|
26
|
+
# Apply all the specification options to the given ActiveRecord relation
|
27
|
+
# @rbs relation: ActiveRecord::Relation
|
28
|
+
# @rbs return: ActiveRecord::Relation
|
29
|
+
def apply_to(relation)
|
30
|
+
rel = relation
|
31
|
+
rel = rel.select(*options[:select]) if options[:select]
|
32
|
+
rel = rel.where(options[:where]) if options[:where]
|
33
|
+
rel = rel.order(options[:order]) if options[:order]
|
34
|
+
rel = rel.group(*options[:group]) if options[:group]
|
35
|
+
rel = rel.limit(options[:limit]) if options[:limit]
|
36
|
+
rel = rel.offset(options[:offset]) if options[:offset]
|
37
|
+
rel = rel.joins(options[:joins]) if options[:joins]
|
38
|
+
rel = rel.left_outer_joins(options[:left_outer_joins]) if options[:left_outer_joins]
|
39
|
+
rel = rel.includes(*options[:includes]) if options[:includes]
|
40
|
+
rel = rel.preload(*options[:preload]) if options[:preload]
|
41
|
+
rel = rel.eager_load(*options[:eager_load]) if options[:eager_load]
|
42
|
+
rel = rel.distinct if options[:distinct]
|
43
|
+
rel = rel.reorder(options[:reorder]) if options[:reorder]
|
44
|
+
rel = rel.extending(*options[:extending]) if options[:extending]
|
45
|
+
rel = rel.unscope(options[:unscope]) if options[:unscope]
|
46
|
+
rel
|
47
|
+
end
|
48
|
+
|
49
|
+
# Create helpers for each query option
|
50
|
+
|
51
|
+
# @rbs *fields: untyped
|
52
|
+
# @rbs return: Quo::QuerySpecification
|
53
|
+
def select(*fields)
|
54
|
+
merge(select: fields)
|
55
|
+
end
|
56
|
+
|
57
|
+
# @rbs conditions: untyped
|
58
|
+
# @rbs return: Quo::QuerySpecification
|
59
|
+
def where(conditions)
|
60
|
+
merge(where: conditions)
|
61
|
+
end
|
62
|
+
|
63
|
+
# @rbs order_clause: untyped
|
64
|
+
# @rbs return: Quo::QuerySpecification
|
65
|
+
def order(order_clause)
|
66
|
+
merge(order: order_clause)
|
67
|
+
end
|
68
|
+
|
69
|
+
# @rbs *columns: untyped
|
70
|
+
# @rbs return: Quo::QuerySpecification
|
71
|
+
def group(*columns)
|
72
|
+
merge(group: columns)
|
73
|
+
end
|
74
|
+
|
75
|
+
# @rbs value: Integer
|
76
|
+
# @rbs return: Quo::QuerySpecification
|
77
|
+
def limit(value)
|
78
|
+
merge(limit: value)
|
79
|
+
end
|
80
|
+
|
81
|
+
# @rbs value: Integer
|
82
|
+
# @rbs return: Quo::QuerySpecification
|
83
|
+
def offset(value)
|
84
|
+
merge(offset: value)
|
85
|
+
end
|
86
|
+
|
87
|
+
# @rbs tables: untyped
|
88
|
+
# @rbs return: Quo::QuerySpecification
|
89
|
+
def joins(tables)
|
90
|
+
merge(joins: tables)
|
91
|
+
end
|
92
|
+
|
93
|
+
# @rbs tables: untyped
|
94
|
+
# @rbs return: Quo::QuerySpecification
|
95
|
+
def left_outer_joins(tables)
|
96
|
+
merge(left_outer_joins: tables)
|
97
|
+
end
|
98
|
+
|
99
|
+
# @rbs *associations: untyped
|
100
|
+
# @rbs return: Quo::QuerySpecification
|
101
|
+
def includes(*associations)
|
102
|
+
merge(includes: associations)
|
103
|
+
end
|
104
|
+
|
105
|
+
# @rbs *associations: untyped
|
106
|
+
# @rbs return: Quo::QuerySpecification
|
107
|
+
def preload(*associations)
|
108
|
+
merge(preload: associations)
|
109
|
+
end
|
110
|
+
|
111
|
+
# @rbs *associations: untyped
|
112
|
+
# @rbs return: Quo::QuerySpecification
|
113
|
+
def eager_load(*associations)
|
114
|
+
merge(eager_load: associations)
|
115
|
+
end
|
116
|
+
|
117
|
+
# @rbs enabled: bool
|
118
|
+
# @rbs return: Quo::QuerySpecification
|
119
|
+
def distinct(enabled = true)
|
120
|
+
merge(distinct: enabled)
|
121
|
+
end
|
122
|
+
|
123
|
+
# @rbs order_clause: untyped
|
124
|
+
# @rbs return: Quo::QuerySpecification
|
125
|
+
def reorder(order_clause)
|
126
|
+
merge(reorder: order_clause)
|
127
|
+
end
|
128
|
+
|
129
|
+
# @rbs *modules: untyped
|
130
|
+
# @rbs return: Quo::QuerySpecification
|
131
|
+
def extending(*modules)
|
132
|
+
merge(extending: modules)
|
133
|
+
end
|
134
|
+
|
135
|
+
# @rbs *args: untyped
|
136
|
+
# @rbs return: Quo::QuerySpecification
|
137
|
+
def unscope(*args)
|
138
|
+
merge(unscope: args)
|
139
|
+
end
|
140
|
+
|
141
|
+
# Builds a new specification from a hash of options
|
142
|
+
# @rbs options: Hash[Symbol, untyped]
|
143
|
+
# @rbs return: Quo::QuerySpecification
|
144
|
+
def self.build(options = {})
|
145
|
+
new(options)
|
146
|
+
end
|
147
|
+
|
148
|
+
# Returns a blank specification
|
149
|
+
# @rbs return: Quo::QuerySpecification
|
150
|
+
def self.blank
|
151
|
+
@blank ||= new
|
152
|
+
end
|
153
|
+
end
|
154
|
+
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
|
-
|
4
|
-
require_relative "./utilities/callstack"
|
3
|
+
# rbs_inline: enabled
|
5
4
|
|
6
5
|
module Quo
|
7
6
|
class Results
|
8
|
-
|
9
|
-
|
7
|
+
def empty? #: bool
|
8
|
+
!exists?
|
9
|
+
end
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
@transformer = transformer
|
11
|
+
# Alias for total_count
|
12
|
+
def count #: Integer
|
13
|
+
total_count
|
15
14
|
end
|
16
15
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
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
|
-
|
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 =
|
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
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
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
|
data/lib/quo/rspec/helpers.rb
CHANGED
@@ -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
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
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
data/lib/quo.rb
CHANGED
@@ -1,40 +1,33 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# rbs_inline: enabled
|
4
|
+
|
3
5
|
require_relative "quo/version"
|
4
|
-
|
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
|
-
|
15
|
-
def configuration
|
16
|
-
@configuration ||= Configuration.new
|
17
|
-
end
|
9
|
+
extend ActiveSupport::Autoload
|
18
10
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
11
|
+
autoload :Query
|
12
|
+
autoload :Preloadable
|
13
|
+
autoload :RelationBackedQuerySpecification
|
14
|
+
autoload :RelationBackedQuery
|
15
|
+
autoload :Results
|
16
|
+
autoload :RelationResults
|
17
|
+
autoload :CollectionResults
|
18
|
+
autoload :ComposedQuery
|
19
|
+
autoload :CollectionBackedQuery
|
24
20
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
21
|
+
mattr_accessor :relation_backed_query_base_class, default: "Quo::RelationBackedQuery"
|
22
|
+
mattr_accessor :collection_backed_query_base_class, default: "Quo::CollectionBackedQuery"
|
23
|
+
mattr_accessor :max_page_size, default: 200
|
24
|
+
mattr_accessor :default_page_size, default: 20
|
25
|
+
|
26
|
+
def self.relation_backed_query_base_class #: Quo::RelationBackedQuery
|
27
|
+
@@relation_backed_query_base_class.constantize
|
28
|
+
end
|
31
29
|
|
32
|
-
|
33
|
-
|
34
|
-
@query_show_callstack_size = 10
|
35
|
-
@logger = nil
|
36
|
-
@max_page_size = 200
|
37
|
-
@default_page_size = 20
|
38
|
-
end
|
30
|
+
def self.collection_backed_query_base_class #: Quo::CollectionBackedQuery
|
31
|
+
@@collection_backed_query_base_class.constantize
|
39
32
|
end
|
40
33
|
end
|
data/rbs_collection.yaml
CHANGED
@@ -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
|