quo 0.3.1 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +18 -24
- data/Steepfile +1 -0
- data/lib/quo/eager_query.rb +11 -8
- data/lib/quo/loaded_query.rb +18 -0
- data/lib/quo/merged_query.rb +0 -18
- data/lib/quo/query.rb +42 -24
- data/lib/quo/query_composer.rb +36 -22
- data/lib/quo/{enumerator.rb → results.rb} +4 -3
- data/lib/quo/rspec/helpers.rb +2 -2
- data/lib/quo/utilities/callstack.rb +1 -1
- data/lib/quo/utilities/wrap.rb +1 -1
- data/lib/quo/version.rb +1 -1
- data/lib/quo/wrapped_query.rb +4 -16
- data/lib/quo.rb +9 -2
- data/sig/quo/eager_query.rbs +5 -3
- data/sig/quo/loaded_query.rbs +7 -0
- data/sig/quo/merged_query.rbs +3 -1
- data/sig/quo/query.rbs +5 -5
- data/sig/quo/query_composer.rbs +16 -2
- data/sig/quo/{enumerator.rbs → results.rbs} +2 -2
- data/sig/quo/wrapped_query.rbs +2 -2
- data/sig/quo.rbs +8 -2
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 071f43a86ac28245731999ddf6f605c89802b71e3d51139d44263214ad25dbd5
|
4
|
+
data.tar.gz: 5eaf5d72a701679c599e5d07f60e8f1c7c9eb1f2e00a7f8ad1503270bc9cda64
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ed91b9a82feb1c8f165672ffa4d2b1212ea7e8780cb85980f82353eca7fdfb247e67101fb6156ceaad65be94f27406daa4a5832e4950ab0204f7a9dc326329a7
|
7
|
+
data.tar.gz: 503525140bd10ed28817e61dc0a2de8ef4e60ca32805427b72763a039982fd069a147ce8eb18d91896ac83202645a12092a8b186b530c97322f465baeeba687a
|
data/README.md
CHANGED
@@ -201,50 +201,44 @@ Specify extra options to enable pagination:
|
|
201
201
|
* `page`: the current page number to fetch
|
202
202
|
* `page_size`: the number of elements to fetch in the page
|
203
203
|
|
204
|
-
|
204
|
+
### `Quo::EagerQuery` & `Quo::LoadedQuery` objects
|
205
205
|
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
For example, the Query below executes the query inside on the first call and memoises the resulting data. Note
|
211
|
-
however that this then means that this Query is not reusuable to `merge` with other ActiveRecord queries. If it is
|
212
|
-
`compose`d with other Query objects then it will be seen as an array-like, and concatenated to whatever it is being
|
213
|
-
joined to.
|
206
|
+
`Quo::EagerQuery` is a subclass of `Quo::Query` which can be used to create query objects which are 'eager loaded' by
|
207
|
+
default. This is useful for encapsulating data that doesn't come from an ActiveRecord query or queries that
|
208
|
+
execute immediately. Subclass EasyQuery and override `collection` to return the data you want to encapsulate.
|
214
209
|
|
215
210
|
```ruby
|
216
|
-
class
|
217
|
-
def
|
218
|
-
|
211
|
+
class MyEagerQuery < Quo::EagerQuery
|
212
|
+
def collection
|
213
|
+
[1, 2, 3]
|
219
214
|
end
|
220
215
|
end
|
221
|
-
|
222
|
-
q = CachedTags.new(active: false)
|
216
|
+
q = MyEagerQuery.new
|
223
217
|
q.eager? # is it 'eager'? Yes it is!
|
224
|
-
q.count #
|
218
|
+
q.count # '3'
|
225
219
|
```
|
226
220
|
|
227
|
-
|
228
|
-
|
229
|
-
`Quo::EagerQuery` is a subclass of `Quo::Query` which takes a data value on instantiation and returns it on calls to `query`
|
221
|
+
Sometimes it is useful to create similar Queries without needing to create a explicit subclass of your own. For this
|
222
|
+
use `Quo::LoadedQuery`:
|
230
223
|
|
231
224
|
```ruby
|
232
|
-
q = Quo::
|
225
|
+
q = Quo::LoadedQuery.new([1, 2, 3])
|
233
226
|
q.eager? # is it 'eager'? Yes it is!
|
234
227
|
q.count # '3'
|
235
228
|
```
|
236
229
|
|
237
|
-
This is useful to create eager loaded Queries without needing to create a explicit subclass of your own.
|
238
|
-
|
239
230
|
`Quo::EagerQuery` also uses `total_count` option value as the specified 'total count', useful when the data is
|
240
231
|
actually just a page of the data and not the total count.
|
241
232
|
|
242
233
|
Example of an EagerQuery used to wrap a page of enumerable data:
|
243
234
|
|
244
235
|
```ruby
|
245
|
-
Quo::
|
236
|
+
Quo::LoadedQuery.new(my_data, total_count: 100, page: current_page)
|
246
237
|
```
|
247
238
|
|
239
|
+
If a loaded query is `compose`d with other Query objects then it will be seen as an array-like, and concatenated to whatever
|
240
|
+
results are returned from the other queries. An loaded or eager query will force all other queries to be eager loaded.
|
241
|
+
|
248
242
|
### Composition
|
249
243
|
|
250
244
|
Examples of composition of eager loaded queries
|
@@ -262,7 +256,7 @@ composed.last
|
|
262
256
|
composed.first
|
263
257
|
# => #<Tag id: ...>
|
264
258
|
|
265
|
-
Quo::
|
259
|
+
Quo::LoadedQuery.new([3, 4]).compose(Quo::LoadedQuery.new([1, 2])).last
|
266
260
|
# => 2
|
267
261
|
Quo::Query.compose([1, 2], [3, 4]).last
|
268
262
|
# => 4
|
@@ -292,7 +286,7 @@ maybe desirable.
|
|
292
286
|
|
293
287
|
The spec helper method `stub_query(query_class, {results: ..., with: ...})` can do this for you.
|
294
288
|
|
295
|
-
It stubs `.new` on the Query object and returns instances of `
|
289
|
+
It stubs `.new` on the Query object and returns instances of `LoadedQuery` instead with the given `results`.
|
296
290
|
The `with` option is passed to the Query object on initialisation and used when setting up the method stub on the
|
297
291
|
query class.
|
298
292
|
|
data/Steepfile
CHANGED
data/lib/quo/eager_query.rb
CHANGED
@@ -2,25 +2,22 @@
|
|
2
2
|
|
3
3
|
module Quo
|
4
4
|
class EagerQuery < Quo::Query
|
5
|
-
def initialize(**options)
|
6
|
-
@collection = Array.wrap(options[:collection])
|
7
|
-
super(**options.except(:collection))
|
8
|
-
end
|
9
|
-
|
10
5
|
# Optionally return the `total_count` option if it has been set.
|
11
6
|
# This is useful when the total count is known and not equal to size
|
12
7
|
# of wrapped collection.
|
13
8
|
def count
|
14
9
|
options[:total_count] || super
|
15
10
|
end
|
16
|
-
alias_method :total_count, :count
|
17
|
-
alias_method :size, :count
|
18
11
|
|
19
12
|
# Is this query object paged? (when no total count)
|
20
13
|
def paged?
|
21
14
|
options[:total_count].nil? && current_page.present?
|
22
15
|
end
|
23
16
|
|
17
|
+
def collection
|
18
|
+
raise NotImplementedError, "EagerQuery objects must define a 'collection' method"
|
19
|
+
end
|
20
|
+
|
24
21
|
def query
|
25
22
|
preload_includes(collection) if options[:includes]
|
26
23
|
collection
|
@@ -36,7 +33,13 @@ module Quo
|
|
36
33
|
|
37
34
|
private
|
38
35
|
|
39
|
-
|
36
|
+
def underlying_query
|
37
|
+
unwrap_relation(query)
|
38
|
+
end
|
39
|
+
|
40
|
+
def unwrap_relation(query)
|
41
|
+
query.is_a?(Quo::Query) ? query.unwrap : query
|
42
|
+
end
|
40
43
|
|
41
44
|
def preload_includes(records, preload = nil)
|
42
45
|
::ActiveRecord::Associations::Preloader.new(
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Quo
|
4
|
+
class LoadedQuery < Quo::EagerQuery
|
5
|
+
def initialize(collection, **options)
|
6
|
+
@collection = collection
|
7
|
+
super(**options)
|
8
|
+
end
|
9
|
+
|
10
|
+
def copy(**options)
|
11
|
+
self.class.new(@collection, **@options.merge(options))
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
attr_reader :collection
|
17
|
+
end
|
18
|
+
end
|
data/lib/quo/merged_query.rb
CHANGED
@@ -2,24 +2,6 @@
|
|
2
2
|
|
3
3
|
module Quo
|
4
4
|
class MergedQuery < Quo::Query
|
5
|
-
class << self
|
6
|
-
def call(**options)
|
7
|
-
build_from_options(**options).first
|
8
|
-
end
|
9
|
-
|
10
|
-
def call!(**options)
|
11
|
-
build_from_options(**options).first!
|
12
|
-
end
|
13
|
-
|
14
|
-
def build_from_options(**options)
|
15
|
-
merged_query = options[:merged_query]
|
16
|
-
left = options[:left]
|
17
|
-
right = options[:right]
|
18
|
-
raise ArgumentError "MergedQuery needs the merged result and operands" unless merged_query && left && right
|
19
|
-
new(merged_query, left, right, **options)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
5
|
def initialize(merged_query, left, right, **options)
|
24
6
|
@merged_query = merged_query
|
25
7
|
@left = left
|
data/lib/quo/query.rb
CHANGED
@@ -28,7 +28,7 @@ module Quo
|
|
28
28
|
def initialize(**options)
|
29
29
|
@options = options
|
30
30
|
@current_page = options[:page]&.to_i || options[:current_page]&.to_i
|
31
|
-
@page_size = options[:page_size]&.to_i || 20
|
31
|
+
@page_size = options[:page_size]&.to_i || Quo.configuration.default_page_size || 20
|
32
32
|
end
|
33
33
|
|
34
34
|
# Returns a active record query, or a Quo::Query instance
|
@@ -93,57 +93,60 @@ module Quo
|
|
93
93
|
delegate :model, :klass, to: :underlying_query
|
94
94
|
|
95
95
|
# Get first elements
|
96
|
-
def first(
|
96
|
+
def first(limit = nil)
|
97
97
|
if transform?
|
98
|
-
res = query_with_logging.first(
|
98
|
+
res = query_with_logging.first(limit)
|
99
99
|
if res.is_a? Array
|
100
|
-
res.map.with_index { |r, i| transformer
|
100
|
+
res.map.with_index { |r, i| transformer&.call(r, i) }
|
101
101
|
elsif !res.nil?
|
102
|
-
transformer
|
102
|
+
transformer&.call(query_with_logging.first(limit))
|
103
103
|
end
|
104
|
+
elsif limit
|
105
|
+
query_with_logging.first(limit)
|
104
106
|
else
|
105
|
-
|
107
|
+
# Array#first will not take nil as a limit
|
108
|
+
query_with_logging.first
|
106
109
|
end
|
107
110
|
end
|
108
111
|
|
109
|
-
def first!(
|
110
|
-
item = first(
|
112
|
+
def first!(limit = nil)
|
113
|
+
item = first(limit)
|
111
114
|
raise ActiveRecord::RecordNotFound, "No item could be found!" unless item
|
112
115
|
item
|
113
116
|
end
|
114
117
|
|
115
118
|
# Get last elements
|
116
|
-
def last(
|
119
|
+
def last(limit = nil)
|
117
120
|
if transform?
|
118
|
-
res = query_with_logging.last(
|
121
|
+
res = query_with_logging.last(limit)
|
119
122
|
if res.is_a? Array
|
120
|
-
res.map.with_index { |r, i| transformer
|
123
|
+
res.map.with_index { |r, i| transformer&.call(r, i) }
|
121
124
|
elsif !res.nil?
|
122
|
-
transformer
|
125
|
+
transformer&.call(res)
|
123
126
|
end
|
127
|
+
elsif limit
|
128
|
+
query_with_logging.last(limit)
|
124
129
|
else
|
125
|
-
query_with_logging.last
|
130
|
+
query_with_logging.last
|
126
131
|
end
|
127
132
|
end
|
128
133
|
|
129
134
|
# Convert to array
|
130
135
|
def to_a
|
131
136
|
arr = query_with_logging.to_a
|
132
|
-
transform? ? arr.map.with_index { |r, i| transformer
|
137
|
+
transform? ? arr.map.with_index { |r, i| transformer&.call(r, i) } : arr
|
133
138
|
end
|
134
139
|
|
135
|
-
# Convert to EagerQuery, and load all data
|
136
140
|
def to_eager(more_opts = {})
|
137
|
-
Quo::
|
141
|
+
Quo::LoadedQuery.new(to_a, **options.merge(more_opts))
|
138
142
|
end
|
139
143
|
alias_method :load, :to_eager
|
140
144
|
|
141
|
-
|
142
|
-
|
143
|
-
Quo::Enumerator.new(self, transformer: transformer)
|
145
|
+
def results
|
146
|
+
Quo::Results.new(self, transformer: transformer)
|
144
147
|
end
|
145
148
|
|
146
|
-
# Some convenience methods for
|
149
|
+
# Some convenience methods for working with results
|
147
150
|
delegate :each,
|
148
151
|
:map,
|
149
152
|
:flat_map,
|
@@ -151,8 +154,9 @@ module Quo
|
|
151
154
|
:reject,
|
152
155
|
:filter,
|
153
156
|
:find,
|
157
|
+
:include?,
|
154
158
|
:each_with_object,
|
155
|
-
to: :
|
159
|
+
to: :results
|
156
160
|
|
157
161
|
# Set a block used to transform data after query fetching
|
158
162
|
def transform(&block)
|
@@ -226,7 +230,11 @@ module Quo
|
|
226
230
|
|
227
231
|
def offset
|
228
232
|
per_page = sanitised_page_size
|
229
|
-
page = current_page&.positive?
|
233
|
+
page = if current_page && current_page&.positive?
|
234
|
+
current_page
|
235
|
+
else
|
236
|
+
1
|
237
|
+
end
|
230
238
|
per_page * (page - 1)
|
231
239
|
end
|
232
240
|
|
@@ -238,7 +246,17 @@ module Quo
|
|
238
246
|
end
|
239
247
|
|
240
248
|
def sanitised_page_size
|
241
|
-
|
249
|
+
if page_size && page_size.positive?
|
250
|
+
given_size = page_size.to_i
|
251
|
+
max_page_size = Quo.configuration.max_page_size || 200
|
252
|
+
if given_size > max_page_size
|
253
|
+
max_page_size
|
254
|
+
else
|
255
|
+
given_size
|
256
|
+
end
|
257
|
+
else
|
258
|
+
Quo.configuration.default_page_size || 20
|
259
|
+
end
|
242
260
|
end
|
243
261
|
|
244
262
|
def query_with_logging
|
@@ -268,7 +286,7 @@ module Quo
|
|
268
286
|
end
|
269
287
|
|
270
288
|
def test_eager(rel)
|
271
|
-
rel.is_a?(Enumerable) && !test_relation(rel)
|
289
|
+
rel.is_a?(Quo::LoadedQuery) || (rel.is_a?(Enumerable) && !test_relation(rel))
|
272
290
|
end
|
273
291
|
|
274
292
|
def test_relation(rel)
|
data/lib/quo/query_composer.rb
CHANGED
@@ -5,6 +5,10 @@ module Quo
|
|
5
5
|
def initialize(left, right, joins = nil)
|
6
6
|
@left = left
|
7
7
|
@right = right
|
8
|
+
@unwrapped_left = unwrap_relation(left)
|
9
|
+
@unwrapped_right = unwrap_relation(right)
|
10
|
+
@left_relation = @unwrapped_left.is_a?(::ActiveRecord::Relation)
|
11
|
+
@right_relation = @unwrapped_right.is_a?(::ActiveRecord::Relation)
|
8
12
|
@joins = joins
|
9
13
|
end
|
10
14
|
|
@@ -19,22 +23,28 @@ module Quo
|
|
19
23
|
|
20
24
|
private
|
21
25
|
|
22
|
-
attr_reader :left, :right, :joins
|
26
|
+
attr_reader :left, :right, :joins, :unwrapped_left, :unwrapped_right
|
23
27
|
|
24
|
-
def
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
28
|
+
def left_relation?
|
29
|
+
@left_relation
|
30
|
+
end
|
31
|
+
|
32
|
+
def right_relation?
|
33
|
+
@right_relation
|
34
|
+
end
|
29
35
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
elsif
|
35
|
-
|
36
|
-
elsif
|
37
|
-
|
36
|
+
def merge_left_and_right
|
37
|
+
# FIXME: Skipping type checks here, as not sure how to make this type check with RBS
|
38
|
+
__skip__ = if both_relations?
|
39
|
+
apply_joins(unwrapped_left, joins).merge(unwrapped_right)
|
40
|
+
elsif left_relation_right_enumerable?
|
41
|
+
unwrapped_left.to_a + unwrapped_right
|
42
|
+
elsif left_enumerable_right_relation? && unwrapped_left.respond_to?(:+)
|
43
|
+
unwrapped_left + unwrapped_right.to_a
|
44
|
+
elsif unwrapped_left.respond_to?(:+)
|
45
|
+
unwrapped_left + unwrapped_right
|
46
|
+
else
|
47
|
+
raise ArgumentError, "Cannot merge #{left.class} with #{right.class}"
|
38
48
|
end
|
39
49
|
end
|
40
50
|
|
@@ -49,16 +59,20 @@ module Quo
|
|
49
59
|
query.is_a?(Quo::Query) ? query.unwrap : query
|
50
60
|
end
|
51
61
|
|
52
|
-
def relation_type?(query)
|
53
|
-
if query.is_a?(::Quo::Query)
|
54
|
-
query.relation?
|
55
|
-
else
|
56
|
-
query.is_a?(::ActiveRecord::Relation)
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
62
|
def apply_joins(left_rel, joins)
|
61
63
|
joins.present? ? left_rel.joins(joins) : left_rel
|
62
64
|
end
|
65
|
+
|
66
|
+
def both_relations?
|
67
|
+
left_relation? && right_relation?
|
68
|
+
end
|
69
|
+
|
70
|
+
def left_relation_right_enumerable?
|
71
|
+
left_relation? && !right_relation?
|
72
|
+
end
|
73
|
+
|
74
|
+
def left_enumerable_right_relation?
|
75
|
+
!left_relation? && right_relation?
|
76
|
+
end
|
63
77
|
end
|
64
78
|
end
|
@@ -4,7 +4,7 @@ require "forwardable"
|
|
4
4
|
require_relative "./utilities/callstack"
|
5
5
|
|
6
6
|
module Quo
|
7
|
-
class
|
7
|
+
class Results
|
8
8
|
extend Forwardable
|
9
9
|
include Quo::Utilities::Callstack
|
10
10
|
|
@@ -28,7 +28,7 @@ module Quo
|
|
28
28
|
grouped = unwrapped.group_by do |*block_args|
|
29
29
|
x = block_args.first
|
30
30
|
transformed = transformer ? transformer.call(x) : x
|
31
|
-
block.call(transformed, *block_args[1..])
|
31
|
+
block ? block.call(transformed, *(block_args[1..] || [])) : transformed
|
32
32
|
end
|
33
33
|
|
34
34
|
grouped.tap do |groups|
|
@@ -51,7 +51,8 @@ module Quo
|
|
51
51
|
end
|
52
52
|
else
|
53
53
|
raw = unwrapped.send(method, *args, **kwargs)
|
54
|
-
|
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)
|
55
56
|
transform_results(raw)
|
56
57
|
end
|
57
58
|
else
|
data/lib/quo/rspec/helpers.rb
CHANGED
@@ -9,10 +9,10 @@ module Quo
|
|
9
9
|
unless with.nil?
|
10
10
|
return(
|
11
11
|
allow(query_class).to receive(:new)
|
12
|
-
.with(with) { ::Quo::
|
12
|
+
.with(with) { ::Quo::LoadedQuery.new(results) }
|
13
13
|
)
|
14
14
|
end
|
15
|
-
allow(query_class).to receive(:new) { ::Quo::
|
15
|
+
allow(query_class).to receive(:new) { ::Quo::LoadedQuery.new(results) }
|
16
16
|
end
|
17
17
|
end
|
18
18
|
end
|
@@ -12,7 +12,7 @@ module Quo
|
|
12
12
|
stack = Kernel.caller.grep_v(exclude).map { |l| l.gsub(working_dir + "/", "") }
|
13
13
|
stack_to_display = stack[0..callstack_size]
|
14
14
|
message = "\n[Query stack]: -> #{stack_to_display&.join("\n &> ")}\n"
|
15
|
-
message += " (truncated to #{callstack_size} most recent)" if stack.size > callstack_size
|
15
|
+
message += " (truncated to #{callstack_size} most recent)" if callstack_size && stack.size > callstack_size
|
16
16
|
Quo.configuration.logger&.info(message)
|
17
17
|
end
|
18
18
|
end
|
data/lib/quo/utilities/wrap.rb
CHANGED
@@ -15,7 +15,7 @@ module Quo
|
|
15
15
|
if query_rel_or_data.is_a? ActiveRecord::Relation
|
16
16
|
Quo::WrappedQuery.new(query_rel_or_data, **options)
|
17
17
|
else
|
18
|
-
Quo::
|
18
|
+
Quo::LoadedQuery.new(query_rel_or_data, **options)
|
19
19
|
end
|
20
20
|
end
|
21
21
|
end
|
data/lib/quo/version.rb
CHANGED
data/lib/quo/wrapped_query.rb
CHANGED
@@ -2,27 +2,15 @@
|
|
2
2
|
|
3
3
|
module Quo
|
4
4
|
class WrappedQuery < Quo::Query
|
5
|
-
class << self
|
6
|
-
def call(**options)
|
7
|
-
build_from_options(**options).first
|
8
|
-
end
|
9
|
-
|
10
|
-
def call!(**options)
|
11
|
-
build_from_options(**options).first!
|
12
|
-
end
|
13
|
-
|
14
|
-
def build_from_options(**options)
|
15
|
-
query = options[:wrapped_query]
|
16
|
-
raise ArgumentError "WrappedQuery needs a scope" unless query
|
17
|
-
new(query, **options)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
5
|
def initialize(wrapped_query, **options)
|
22
6
|
@wrapped_query = wrapped_query
|
23
7
|
super(**options)
|
24
8
|
end
|
25
9
|
|
10
|
+
def copy(**options)
|
11
|
+
self.class.new(query, **@options.merge(options))
|
12
|
+
end
|
13
|
+
|
26
14
|
def query
|
27
15
|
@wrapped_query
|
28
16
|
end
|
data/lib/quo.rb
CHANGED
@@ -4,10 +4,11 @@ require_relative "quo/version"
|
|
4
4
|
require_relative "quo/railtie" if defined?(Rails)
|
5
5
|
require_relative "quo/query"
|
6
6
|
require_relative "quo/eager_query"
|
7
|
+
require_relative "quo/loaded_query"
|
7
8
|
require_relative "quo/merged_query"
|
8
9
|
require_relative "quo/wrapped_query"
|
9
10
|
require_relative "quo/query_composer"
|
10
|
-
require_relative "quo/
|
11
|
+
require_relative "quo/results"
|
11
12
|
|
12
13
|
module Quo
|
13
14
|
class << self
|
@@ -22,12 +23,18 @@ module Quo
|
|
22
23
|
end
|
23
24
|
|
24
25
|
class Configuration
|
25
|
-
attr_accessor :formatted_query_log,
|
26
|
+
attr_accessor :formatted_query_log,
|
27
|
+
:query_show_callstack_size,
|
28
|
+
:logger,
|
29
|
+
:max_page_size,
|
30
|
+
:default_page_size
|
26
31
|
|
27
32
|
def initialize
|
28
33
|
@formatted_query_log = true
|
29
34
|
@query_show_callstack_size = 10
|
30
35
|
@logger = nil
|
36
|
+
@max_page_size = 200
|
37
|
+
@default_page_size = 20
|
31
38
|
end
|
32
39
|
end
|
33
40
|
end
|
data/sig/quo/eager_query.rbs
CHANGED
@@ -1,13 +1,15 @@
|
|
1
1
|
module Quo
|
2
2
|
class EagerQuery < Quo::Query
|
3
|
-
def
|
4
|
-
def query: () ->
|
3
|
+
def collection: () -> loadedQueryOrEnumerable
|
4
|
+
def query: () -> loadedQueryOrEnumerable
|
5
|
+
|
5
6
|
def relation?: () -> false
|
6
7
|
def eager?: () -> true
|
7
|
-
attr_reader collection: enumerable
|
8
8
|
|
9
9
|
private
|
10
10
|
|
11
11
|
def preload_includes: (untyped records, ?untyped? preload) -> untyped
|
12
|
+
def underlying_query: () -> enumerable
|
13
|
+
def unwrap_relation: (loadedQueryOrEnumerable collection) -> enumerable
|
12
14
|
end
|
13
15
|
end
|
data/sig/quo/merged_query.rbs
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
module Quo
|
2
2
|
class MergedQuery < Quo::Query
|
3
|
+
def self.build_from_options: (queryOptions) -> MergedQuery
|
4
|
+
|
3
5
|
def initialize: (relOrEnumerable merged, composable left, composable right, **untyped options) -> void
|
4
6
|
|
5
7
|
@merged_query: relOrEnumerable
|
6
8
|
|
7
|
-
def query: () ->
|
9
|
+
def query: () -> relOrEnumerable
|
8
10
|
|
9
11
|
def to_s: () -> ::String
|
10
12
|
|
data/sig/quo/query.rbs
CHANGED
@@ -40,13 +40,13 @@ module Quo
|
|
40
40
|
|
41
41
|
alias size count
|
42
42
|
def page_count: () -> Integer
|
43
|
-
def first: (
|
44
|
-
def first!: (
|
45
|
-
def last: (
|
43
|
+
def first: (?Integer? limit) -> untyped
|
44
|
+
def first!: (?Integer? limit) -> untyped
|
45
|
+
def last: (?Integer? limit) -> untyped
|
46
46
|
def to_a: () -> Array[untyped]
|
47
47
|
def to_eager: (?::Hash[untyped, untyped] more_opts) -> Quo::EagerQuery
|
48
48
|
alias load to_eager
|
49
|
-
def
|
49
|
+
def results: () -> Quo::Results
|
50
50
|
|
51
51
|
# Set a block used to transform data after query fetching
|
52
52
|
def transform: () ?{ () -> untyped } -> self
|
@@ -70,7 +70,7 @@ module Quo
|
|
70
70
|
def formatted_queries?: () -> bool
|
71
71
|
def trim_query: (String sql) -> String
|
72
72
|
def format_query: (String sql_str) -> String
|
73
|
-
def transformer: () -> (nil | ^(untyped) -> untyped)
|
73
|
+
def transformer: () -> (nil | ^(untyped, ?Integer) -> untyped)
|
74
74
|
def offset: () -> Integer
|
75
75
|
def configured_query: () -> ActiveRecord::Relation
|
76
76
|
def sanitised_page_size: () -> Integer
|
data/sig/quo/query_composer.rbs
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
module Quo
|
2
2
|
class QueryComposer
|
3
|
+
@left_relation: bool
|
4
|
+
@right_relation: bool
|
5
|
+
|
3
6
|
def initialize: (composable left, composable right, ?untyped? joins) -> void
|
4
7
|
def compose: () -> Quo::MergedQuery
|
5
8
|
|
@@ -9,10 +12,21 @@ module Quo
|
|
9
12
|
attr_reader right: composable
|
10
13
|
attr_reader joins: untyped
|
11
14
|
|
12
|
-
|
15
|
+
attr_reader unwrapped_left: relOrEnumerable
|
16
|
+
attr_reader unwrapped_right: relOrEnumerable
|
17
|
+
|
18
|
+
def left_relation?: -> bool
|
19
|
+
|
20
|
+
def merge_left_and_right: () -> relOrEnumerable
|
13
21
|
def merged_options: () -> ::Hash[untyped, untyped]
|
22
|
+
|
23
|
+
def right_relation?: -> bool
|
24
|
+
|
14
25
|
def unwrap_relation: (composable) -> relOrEnumerable
|
15
|
-
def relation_type?: (
|
26
|
+
def relation_type?: (relOrEnumerable) -> bool
|
16
27
|
def apply_joins: (ActiveRecord::Relation left_rel, untyped joins) -> ActiveRecord::Relation
|
28
|
+
def both_relations?: () -> bool
|
29
|
+
def left_relation_right_enumerable?: () -> bool
|
30
|
+
def left_enumerable_right_relation?: () -> bool
|
17
31
|
end
|
18
32
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module Quo
|
2
|
-
class
|
2
|
+
class Results
|
3
3
|
extend Forwardable
|
4
4
|
|
5
5
|
include Quo::Utilities::Callstack
|
@@ -8,7 +8,7 @@ module Quo
|
|
8
8
|
|
9
9
|
@query: Quo::Query
|
10
10
|
|
11
|
-
def group_by: -> Hash[untyped, Array[untyped]]
|
11
|
+
def group_by: () { (untyped, *untyped) -> untyped } -> Hash[untyped, Array[untyped]]
|
12
12
|
|
13
13
|
def respond_to_missing?: (Symbol name, ?bool include_private) -> bool
|
14
14
|
|
data/sig/quo/wrapped_query.rbs
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
module Quo
|
2
2
|
class WrappedQuery < Quo::Query
|
3
|
-
@wrapped_query: ActiveRecord::Relation
|
4
|
-
|
5
3
|
def self.build_from_options: (**untyped options) -> WrappedQuery
|
6
4
|
|
5
|
+
@wrapped_query: ActiveRecord::Relation
|
6
|
+
|
7
7
|
def initialize: (ActiveRecord::Relation query, **untyped options) -> void
|
8
8
|
|
9
9
|
def query: () -> ActiveRecord::Relation
|
data/sig/quo.rbs
CHANGED
@@ -11,11 +11,15 @@ module Quo
|
|
11
11
|
|
12
12
|
type query = Quo::Query
|
13
13
|
type queryOrRel = query | ActiveRecord::Relation
|
14
|
-
|
15
|
-
type enumerable = Array[untyped] | Set[untyped]
|
14
|
+
type enumerable = Object & Enumerable[untyped]
|
16
15
|
type relOrEnumerable = ActiveRecord::Relation | enumerable
|
16
|
+
type loadedQueryOrEnumerable = LoadedQuery | EagerQuery | enumerable
|
17
17
|
type composable = query | relOrEnumerable
|
18
18
|
|
19
|
+
# TODO: how can we do the known options, eg `page` and then allow anything else?
|
20
|
+
# Maybe we should separate out the known options from the unknown options
|
21
|
+
type queryOptions = Hash[Symbol, untyped]
|
22
|
+
|
19
23
|
interface _Logger
|
20
24
|
def info: (String) -> void
|
21
25
|
def error: (String) -> void
|
@@ -26,6 +30,8 @@ module Quo
|
|
26
30
|
attr_accessor formatted_query_log: bool?
|
27
31
|
attr_accessor query_show_callstack_size: Integer?
|
28
32
|
attr_accessor logger: _Logger?
|
33
|
+
attr_accessor max_page_size: Integer?
|
34
|
+
attr_accessor default_page_size: Integer?
|
29
35
|
|
30
36
|
def initialize: () -> void
|
31
37
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: quo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Stephen Ierodiaconou
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-12-
|
11
|
+
date: 2022-12-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -66,11 +66,12 @@ files:
|
|
66
66
|
- Steepfile
|
67
67
|
- lib/quo.rb
|
68
68
|
- lib/quo/eager_query.rb
|
69
|
-
- lib/quo/
|
69
|
+
- lib/quo/loaded_query.rb
|
70
70
|
- lib/quo/merged_query.rb
|
71
71
|
- lib/quo/query.rb
|
72
72
|
- lib/quo/query_composer.rb
|
73
73
|
- lib/quo/railtie.rb
|
74
|
+
- lib/quo/results.rb
|
74
75
|
- lib/quo/rspec/helpers.rb
|
75
76
|
- lib/quo/utilities/callstack.rb
|
76
77
|
- lib/quo/utilities/compose.rb
|
@@ -82,10 +83,11 @@ files:
|
|
82
83
|
- rbs_collection.yaml
|
83
84
|
- sig/quo.rbs
|
84
85
|
- sig/quo/eager_query.rbs
|
85
|
-
- sig/quo/
|
86
|
+
- sig/quo/loaded_query.rbs
|
86
87
|
- sig/quo/merged_query.rbs
|
87
88
|
- sig/quo/query.rbs
|
88
89
|
- sig/quo/query_composer.rbs
|
90
|
+
- sig/quo/results.rbs
|
89
91
|
- sig/quo/utilities/callstack.rbs
|
90
92
|
- sig/quo/utilities/compose.rbs
|
91
93
|
- sig/quo/utilities/sanitize.rbs
|