quo 0.2.0 → 0.3.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6f8a79b64bd0db1439df6ffcfb820786ed082405bb24d56ac2ac08cb47c052b7
4
- data.tar.gz: 0b46427745aa9433130c4ec495cf2c9d79bff517b00ea99f17029b3a2714b604
3
+ metadata.gz: 88c53b53f941762022f3b012abe6fe3e977e125c562f771aca630c28a087c13e
4
+ data.tar.gz: dfdeb96c25d7a3e06fef0524b6c77be0cff1ae94368b39f17d6a3a3c8400e181
5
5
  SHA512:
6
- metadata.gz: 514f649e606616d7a46de0c409b4c3f635c11fe900f179e0f94952a594adb49877e82ced68e9541e2dd398e2b0e35e9ea8ff1c4995701ed8f30361de48f8ae78
7
- data.tar.gz: 7562f9cfc712ac473e6a32bb1c9f5b9e88123fb0abaa696f29dbf24e90dcedaaf716d42e0cd8bf6b8a5594a6f888fbf20f3e2b665ff9dda108ddc7ededfbe9a9
6
+ metadata.gz: 281cad72c46e498166255f5f973fd09dfec37d309e406bccbfe27cd8ae80cfd95321f2dace615d0be36db8b9b9f38b3257e7e2acf3fd81c7f05788daa48d8e9d
7
+ data.tar.gz: f09f1213677fb08bc45ac5c27262afc0692555fe24a0da0547ad37e15661019d92d9e49f7eda7651c9c518334cca2f1195a38e0c7d60b61384240f34046032d6
data/Steepfile CHANGED
@@ -27,8 +27,10 @@
27
27
  # end
28
28
 
29
29
  target :lib do
30
- check "lib/quo"
30
+ check "lib"
31
31
  signature "sig"
32
+ ignore "lib/quo/rspec/*.rb"
33
+ ignore "lib/tasks/*"
32
34
 
33
35
  library "forwardable"
34
36
  end
@@ -21,30 +21,36 @@ module Quo
21
21
  :any?,
22
22
  :none?,
23
23
  :one?,
24
- :tally,
25
- :count,
26
- :group_by,
27
- :partition,
28
- :slice_before,
29
- :slice_after,
30
- :slice_when,
31
- :chunk,
32
- :chunk_while,
33
- :sum,
34
- :zip
24
+ :count
25
+
26
+ def group_by(&block)
27
+ debug_callstack
28
+ grouped = unwrapped.group_by do |*block_args|
29
+ x = block_args.first
30
+ transformed = transformer ? transformer.call(x) : x
31
+ block.call(transformed, *block_args[1..])
32
+ end
33
+
34
+ grouped.tap do |groups|
35
+ groups.transform_values! do |values|
36
+ transformer ? values.map { |x| transformer.call(x) } : values
37
+ end
38
+ end
39
+ end
35
40
 
36
41
  # Delegate other enumerable methods to underlying collection but also transform
37
- def method_missing(method, *args, &block)
42
+ def method_missing(method, *args, **kwargs, &block)
38
43
  if unwrapped.respond_to?(method)
39
44
  debug_callstack
40
45
  if block
41
- unwrapped.send(method, *args) do |*block_args|
46
+ unwrapped.send(method, *args, **kwargs) do |*block_args|
42
47
  x = block_args.first
43
- transformed = transformer.present? ? transformer.call(x) : x
44
- block.call(transformed, *block_args[1..])
48
+ transformed = transformer ? transformer.call(x) : x
49
+ other_args = block_args[1..] || []
50
+ block.call(transformed, *other_args)
45
51
  end
46
52
  else
47
- raw = unwrapped.send(method, *args)
53
+ raw = unwrapped.send(method, *args, **kwargs)
48
54
  return raw if raw.is_a?(Quo::Enumerator) || raw.is_a?(::Enumerator)
49
55
  transform_results(raw)
50
56
  end
@@ -62,7 +68,7 @@ module Quo
62
68
  attr_reader :transformer, :unwrapped
63
69
 
64
70
  def transform_results(results)
65
- return results unless transformer.present?
71
+ return results unless transformer
66
72
 
67
73
  if results.is_a?(Enumerable)
68
74
  results.map.with_index { |item, i| transformer.call(item, i) }
@@ -2,39 +2,52 @@
2
2
 
3
3
  module Quo
4
4
  class MergedQuery < Quo::Query
5
- def initialize(options, source_queries = [])
6
- @source_queries = source_queries
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
+ def initialize(merged_query, left, right, **options)
24
+ @merged_query = merged_query
25
+ @left = left
26
+ @right = right
7
27
  super(**options)
8
28
  end
9
29
 
10
30
  def query
11
- @scope
31
+ @merged_query
12
32
  end
13
33
 
14
- def to_s
15
- left = operand_desc(source_queries_left)
16
- right = operand_desc(source_queries_right)
17
- "Quo::MergedQuery[#{left}, #{right}]"
34
+ def copy(**options)
35
+ self.class.new(query, left, right, **@options.merge(options))
18
36
  end
19
37
 
20
- private
21
-
22
- def source_queries_left
23
- source_queries&.first
38
+ def to_s
39
+ "Quo::MergedQuery[#{operand_desc(left)}, #{operand_desc(right)}]"
24
40
  end
25
41
 
26
- def source_queries_right
27
- source_queries&.last
28
- end
42
+ private
29
43
 
30
- attr_reader :source_queries
44
+ attr_reader :left, :right
31
45
 
32
46
  def operand_desc(operand)
33
- return unless operand
34
47
  if operand.is_a? Quo::MergedQuery
35
48
  operand.to_s
36
49
  else
37
- operand.class.name
50
+ operand.class.name || "(anonymous)"
38
51
  end
39
52
  end
40
53
  end
data/lib/quo/query.rb CHANGED
@@ -29,19 +29,16 @@ module Quo
29
29
  @options = options
30
30
  @current_page = options[:page]&.to_i || options[:current_page]&.to_i
31
31
  @page_size = options[:page_size]&.to_i || 20
32
- @scope = unwrap_relation(options[:scope])
33
32
  end
34
33
 
35
34
  # Returns a active record query, or a Quo::Query instance
36
- # You must provide an implementation of this of pass the 'scope' option on instantiation
37
35
  def query
38
- return @scope unless @scope.nil?
39
36
  raise NotImplementedError, "Query objects must define a 'query' method"
40
37
  end
41
38
 
42
39
  # Combine (compose) this query object with another composeable entity, see notes for `.compose` above.
43
40
  # Compose is aliased as `+`. Can optionally take `joins()` parameters to perform a joins before the merge
44
- def compose(right, joins = nil)
41
+ def compose(right, joins: nil)
45
42
  Quo::QueryComposer.new(self, right, joins).compose
46
43
  end
47
44
 
@@ -147,7 +144,15 @@ module Quo
147
144
  end
148
145
 
149
146
  # Some convenience methods for iterating over the results
150
- delegate :each, :map, :flat_map, :reduce, :reject, :filter, to: :enumerator
147
+ delegate :each,
148
+ :map,
149
+ :flat_map,
150
+ :reduce,
151
+ :reject,
152
+ :filter,
153
+ :find,
154
+ :each_with_object,
155
+ to: :enumerator
151
156
 
152
157
  # Set a block used to transform data after query fetching
153
158
  def transform(&block)
@@ -202,7 +207,7 @@ module Quo
202
207
  private
203
208
 
204
209
  def formatted_queries?
205
- Quo.configuration&.formatted_query_log
210
+ !!Quo.configuration.formatted_query_log
206
211
  end
207
212
 
208
213
  # 'trim' a query, ie remove comments and remove newlines
@@ -221,7 +226,7 @@ module Quo
221
226
 
222
227
  def offset
223
228
  per_page = sanitised_page_size
224
- page = current_page.positive? ? current_page : 1
229
+ page = current_page&.positive? ? current_page : 1
225
230
  per_page * (page - 1)
226
231
  end
227
232
 
@@ -252,7 +257,6 @@ module Quo
252
257
  rel = rel.limit(@options[:limit]) if @options[:limit].present?
253
258
  rel = rel.preload(@options[:preload]) if @options[:preload].present?
254
259
  rel = rel.includes(@options[:includes]) if @options[:includes].present?
255
- rel = rel.joins(@options[:joins]) if @options[:joins].present?
256
260
  rel = rel.select(@options[:select]) if @options[:select].present?
257
261
  end
258
262
  rel
@@ -9,9 +9,11 @@ module Quo
9
9
  end
10
10
 
11
11
  def compose
12
- combined = merge
13
12
  Quo::MergedQuery.new(
14
- merged_options.merge({scope: combined, source_queries: [left, right]})
13
+ merge_left_and_right,
14
+ left,
15
+ right,
16
+ **merged_options
15
17
  )
16
18
  end
17
19
 
@@ -19,22 +21,20 @@ module Quo
19
21
 
20
22
  attr_reader :left, :right, :joins
21
23
 
22
- def merge
24
+ def merge_left_and_right
23
25
  left_rel = unwrap_relation(left)
24
26
  right_rel = unwrap_relation(right)
25
- left_type = relation_type?(left)
26
- right_type = relation_type?(right)
27
+ left_is_relation = relation_type?(left)
28
+ right_is_relation = relation_type?(right)
27
29
 
28
- if both_relations?(left_type, right_type)
30
+ if left_is_relation && right_is_relation
29
31
  apply_joins(left_rel, joins).merge(right_rel)
30
- elsif left_relation_right_eager?(left_type, right_type)
32
+ elsif left_is_relation && !right_is_relation
31
33
  left_rel.to_a + right_rel
32
- elsif left_eager_right_relation?(left_type, right_type) && left_rel.respond_to?(:+)
34
+ elsif !left_is_relation && right_is_relation
33
35
  left_rel + right_rel.to_a
34
- elsif both_eager_loaded?(left_type, right_type) && left_rel.respond_to?(:+)
36
+ elsif !left_is_relation && !right_is_relation
35
37
  left_rel + right_rel
36
- else
37
- raise_error
38
38
  end
39
39
  end
40
40
 
@@ -58,29 +58,7 @@ module Quo
58
58
  end
59
59
 
60
60
  def apply_joins(left_rel, joins)
61
- joins.present? ? left_rel.joins(joins.to_sym) : left_rel
62
- end
63
-
64
- def both_relations?(left_rel_type, right_rel_type)
65
- left_rel_type && right_rel_type
66
- end
67
-
68
- def left_relation_right_eager?(left_rel_type, right_rel_type)
69
- left_rel_type && !right_rel_type
70
- end
71
-
72
- def left_eager_right_relation?(left_rel_type, right_rel_type)
73
- !left_rel_type && right_rel_type
74
- end
75
-
76
- def both_eager_loaded?(left_rel_type, right_rel_type)
77
- !left_rel_type && !right_rel_type
78
- end
79
-
80
- def raise_error
81
- raise ArgumentError, "Unable to composite queries #{left.class.name} and " \
82
- "#{right.class.name}. You cannot compose queries where #query " \
83
- "returns an ActiveRecord::Relation in one and an Enumerable in the other."
61
+ joins.present? ? left_rel.joins(joins) : left_rel
84
62
  end
85
63
  end
86
64
  end
@@ -4,14 +4,15 @@ module Quo
4
4
  module Utilities
5
5
  module Callstack
6
6
  def debug_callstack
7
- return unless Quo.configuration&.query_show_callstack_size&.positive? && Rails.env.development?
8
- max_stack = Quo.configuration.query_show_callstack_size
7
+ return unless Rails.env.development?
8
+ callstack_size = Quo.configuration.query_show_callstack_size
9
+ return unless callstack_size&.positive?
9
10
  working_dir = Dir.pwd
10
11
  exclude = %r{/(gems/|rubies/|query\.rb)}
11
12
  stack = Kernel.caller.grep_v(exclude).map { |l| l.gsub(working_dir + "/", "") }
12
- trace_message = stack[0..max_stack].join("\n &> ")
13
- message = "\n[Query stack]: -> #{trace_message}\n"
14
- message += " (truncated to #{max_stack} most recent)" if stack.size > max_stack
13
+ stack_to_display = stack[0..callstack_size]
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
16
  Quo.configuration.logger&.info(message)
16
17
  end
17
18
  end
@@ -6,7 +6,7 @@ module Quo
6
6
  # These can be Quo::Query, Quo::MergedQuery, Quo::EagerQuery and ActiveRecord::Relations.
7
7
  # See the `README.md` docs for more details.
8
8
  module Compose
9
- def compose(query1, query2, joins = nil)
9
+ def compose(query1, query2, joins: nil)
10
10
  Quo::QueryComposer.new(query1, query2, joins).compose
11
11
  end
12
12
 
@@ -13,7 +13,7 @@ module Quo
13
13
  end
14
14
 
15
15
  if query_rel_or_data.is_a? ActiveRecord::Relation
16
- new(**options.merge(scope: query_rel_or_data))
16
+ Quo::WrappedQuery.new(query_rel_or_data, **options)
17
17
  else
18
18
  Quo::EagerQuery.new(**options.merge(collection: query_rel_or_data))
19
19
  end
data/lib/quo/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Quo
4
- VERSION = "0.2.0"
4
+ VERSION = "0.3.1"
5
5
  end
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Quo
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
+ def initialize(wrapped_query, **options)
22
+ @wrapped_query = wrapped_query
23
+ super(**options)
24
+ end
25
+
26
+ def query
27
+ @wrapped_query
28
+ end
29
+ end
30
+ end
data/lib/quo.rb CHANGED
@@ -5,6 +5,7 @@ require_relative "quo/railtie" if defined?(Rails)
5
5
  require_relative "quo/query"
6
6
  require_relative "quo/eager_query"
7
7
  require_relative "quo/merged_query"
8
+ require_relative "quo/wrapped_query"
8
9
  require_relative "quo/query_composer"
9
10
  require_relative "quo/enumerator"
10
11
 
@@ -0,0 +1,13 @@
1
+ module Quo
2
+ class EagerQuery < Quo::Query
3
+ def initialize: (**untyped options) -> void
4
+ def query: () -> enumerable
5
+ def relation?: () -> false
6
+ def eager?: () -> true
7
+ attr_reader collection: enumerable
8
+
9
+ private
10
+
11
+ def preload_includes: (untyped records, ?untyped? preload) -> untyped
12
+ end
13
+ end
@@ -0,0 +1,22 @@
1
+ module Quo
2
+ class Enumerator
3
+ extend Forwardable
4
+
5
+ include Quo::Utilities::Callstack
6
+
7
+ def initialize: (Quo::Query query, ?transformer: (^(untyped, ?Integer) -> untyped)?) -> void
8
+
9
+ @query: Quo::Query
10
+
11
+ def group_by: -> Hash[untyped, Array[untyped]]
12
+
13
+ def respond_to_missing?: (Symbol name, ?bool include_private) -> bool
14
+
15
+ private
16
+
17
+ attr_reader transformer: (^(untyped, ?Integer) -> untyped)?
18
+ attr_reader unwrapped: relOrEnumerable
19
+
20
+ def transform_results: (untyped) -> untyped
21
+ end
22
+ end
@@ -0,0 +1,17 @@
1
+ module Quo
2
+ class MergedQuery < Quo::Query
3
+ def initialize: (relOrEnumerable merged, composable left, composable right, **untyped options) -> void
4
+
5
+ @merged_query: relOrEnumerable
6
+
7
+ def query: () -> composable
8
+
9
+ def to_s: () -> ::String
10
+
11
+ private
12
+
13
+ attr_reader left: composable
14
+ attr_reader right: composable
15
+ def operand_desc: (composable operand) -> String
16
+ end
17
+ end
data/sig/quo/query.rbs ADDED
@@ -0,0 +1,83 @@
1
+ module Quo
2
+ class Query
3
+ include Quo::Utilities::Callstack
4
+ extend Quo::Utilities::Compose
5
+ extend Quo::Utilities::Sanitize
6
+ extend Quo::Utilities::Wrap
7
+
8
+ @underlying_query: ActiveRecord::Relation
9
+
10
+ def self.call: (**untyped options) -> untyped
11
+ def self.call!: (**untyped options) -> untyped
12
+
13
+ @scope: ActiveRecord::Relation | nil
14
+
15
+ attr_reader current_page: Integer?
16
+ attr_reader page_size: Integer?
17
+ attr_reader options: Hash[untyped, untyped]
18
+
19
+ def initialize: (**untyped options) -> void
20
+ def query: () -> queryOrRel
21
+ def compose: (composable right, ?joins: untyped?) -> Quo::MergedQuery
22
+ alias + compose
23
+
24
+ def copy: (**untyped options) -> Quo::Query
25
+
26
+ def limit: (untyped limit) -> Quo::Query
27
+ def order: (untyped options) -> Quo::Query
28
+ def group: (*untyped options) -> Quo::Query
29
+ def includes: (*untyped options) -> Quo::Query
30
+ def preload: (*untyped options) -> Quo::Query
31
+ def select: (*untyped options) -> Quo::Query
32
+
33
+ def sum: (?untyped column_name) -> Numeric
34
+ def average: (untyped column_name) -> Numeric
35
+ def minimum: (untyped column_name) -> Numeric
36
+ def maximum: (untyped column_name) -> Numeric
37
+ def count: () -> Integer
38
+
39
+ alias total_count count
40
+
41
+ alias size count
42
+ def page_count: () -> Integer
43
+ def first: (*untyped args) -> untyped
44
+ def first!: (*untyped args) -> untyped
45
+ def last: (*untyped args) -> untyped
46
+ def to_a: () -> Array[untyped]
47
+ def to_eager: (?::Hash[untyped, untyped] more_opts) -> Quo::EagerQuery
48
+ alias load to_eager
49
+ def enumerator: () -> Quo::Enumerator
50
+
51
+ # Set a block used to transform data after query fetching
52
+ def transform: () ?{ () -> untyped } -> self
53
+
54
+ def exists?: () -> bool
55
+ def none?: () -> bool
56
+ alias empty? none?
57
+ def relation?: () -> bool
58
+ def eager?: () -> bool
59
+ def paged?: () -> bool
60
+
61
+ def model: () -> (untyped | nil)
62
+ def klass: () -> (untyped | nil)
63
+
64
+ def transform?: () -> bool
65
+ def to_sql: () -> (String | nil)
66
+ def unwrap: () -> ActiveRecord::Relation
67
+
68
+ private
69
+
70
+ def formatted_queries?: () -> bool
71
+ def trim_query: (String sql) -> String
72
+ def format_query: (String sql_str) -> String
73
+ def transformer: () -> (nil | ^(untyped) -> untyped)
74
+ def offset: () -> Integer
75
+ def configured_query: () -> ActiveRecord::Relation
76
+ def sanitised_page_size: () -> Integer
77
+ def query_with_logging: () -> ActiveRecord::Relation
78
+ def underlying_query: () -> ActiveRecord::Relation
79
+ def unwrap_relation: (queryOrRel query) -> ActiveRecord::Relation
80
+ def test_eager: (composable rel) -> bool
81
+ def test_relation: (composable rel) -> bool
82
+ end
83
+ end
@@ -0,0 +1,18 @@
1
+ module Quo
2
+ class QueryComposer
3
+ def initialize: (composable left, composable right, ?untyped? joins) -> void
4
+ def compose: () -> Quo::MergedQuery
5
+
6
+ private
7
+
8
+ attr_reader left: composable
9
+ attr_reader right: composable
10
+ attr_reader joins: untyped
11
+
12
+ def merge_left_and_right: () -> (ActiveRecord::Relation | Array[untyped])
13
+ def merged_options: () -> ::Hash[untyped, untyped]
14
+ def unwrap_relation: (composable) -> relOrEnumerable
15
+ def relation_type?: (composable) -> bool
16
+ def apply_joins: (ActiveRecord::Relation left_rel, untyped joins) -> ActiveRecord::Relation
17
+ end
18
+ end
@@ -0,0 +1,7 @@
1
+ module Quo
2
+ module Utilities
3
+ module Callstack
4
+ def debug_callstack: () -> void
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,8 @@
1
+ module Quo
2
+ module Utilities
3
+ module Compose
4
+ def compose: (composable query1, composable query2, ?joins: untyped?) -> Quo::MergedQuery
5
+ def composable_with?: (queryOrRel query) -> bool
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,9 @@
1
+ module Quo
2
+ module Utilities
3
+ module Sanitize
4
+ def sanitize_sql_for_conditions: (untyped conditions) -> untyped?
5
+ def sanitize_sql_string: (untyped string) -> untyped?
6
+ def sanitize_sql_parameter: (untyped value) -> untyped?
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,11 @@
1
+ module Quo
2
+ module Utilities
3
+ interface _Wrapable
4
+ def new: (**untyped options) -> query
5
+ end
6
+
7
+ module Wrap : _Wrapable
8
+ def wrap: (composable query_rel_or_data, **untyped options) -> query
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ module Quo
2
+ class WrappedQuery < Quo::Query
3
+ @wrapped_query: ActiveRecord::Relation
4
+
5
+ def self.build_from_options: (**untyped options) -> WrappedQuery
6
+
7
+ def initialize: (ActiveRecord::Relation query, **untyped options) -> void
8
+
9
+ def query: () -> ActiveRecord::Relation
10
+ end
11
+ end
data/sig/quo.rbs CHANGED
@@ -1,205 +1,35 @@
1
- module Quo
2
- VERSION: String
3
-
4
- interface _Enumerable
5
- def each: { (untyped) -> void } -> untyped
6
- end
7
-
8
- interface _Collection
9
- include _Enumerable
10
- def is_a?: (Class) -> bool
11
- def class: -> Class
12
- def +: (untyped) -> _Collection
13
- end
14
-
15
- type query = Quo::MergedQuery | Quo::EagerQuery | Quo::Query
16
- type merge_composable = query | ActiveRecord::Relation
17
- type enumerable = _Collection
18
- type query_like = ActiveRecord::Relation | enumerable
19
- type composable = query | query_like
20
-
21
- module Utilities
22
- module Callstack
23
- def debug_callstack: () -> void
24
- end
25
-
26
- module Compose
27
- # Combine two query-like or composeable entities:
28
- # These can be Quo::Query, Quo::MergedQuery, Quo::EagerQuery and ActiveRecord::Relations.
29
- # See the `README.md` docs for more details.
30
- def compose: (composable query1, composable query2, ?untyped? joins) -> Quo::MergedQuery
31
-
32
- # Determines if the object `query` is something which can be composed with query objects
33
- def composable_with?: (merge_composable query) -> bool
34
- end
35
-
36
- module Sanitize
37
- def sanitize_sql_for_conditions: (untyped conditions) -> (untyped | nil)
38
-
39
- def sanitize_sql_string: (untyped string) -> (untyped | nil)
40
-
41
- def sanitize_sql_parameter: (untyped value) -> (untyped | nil)
1
+ module ActiveRecord
2
+ module Associations
3
+ class Preloader
4
+ def initialize: (records: untyped, associations: untyped, ?scope: untyped, ?available_records: Array[untyped], ?associate_by_default: bool) -> void
42
5
  end
43
-
44
- interface _Wrapable
45
- def new: (**untyped options) -> query
46
- end
47
-
48
- module Wrap : _Wrapable
49
- def wrap: (composable query_rel_or_data, **untyped options) -> query
50
- end
51
-
52
- end
53
-
54
- class Enumerator
55
- extend Forwardable
56
-
57
- include Quo::Utilities::Callstack
58
-
59
- def initialize: (Quo::Query query, ?transformer: ^(untyped, ?Integer) -> untyped) -> void
60
-
61
- @query: Quo::Query
62
-
63
- def respond_to_missing?: (Symbol name, ?bool include_private) -> bool
64
-
65
- private
66
-
67
- attr_reader transformer: ^(untyped, ?Integer) -> untyped
68
- attr_reader unwrapped: ActiveRecord::Relation
69
-
70
- def transform_results: (untyped) -> untyped
71
6
  end
7
+ end
72
8
 
9
+ module Quo
10
+ VERSION: String
73
11
 
74
- class Query
75
- include Quo::Utilities::Callstack
76
- extend Quo::Utilities::Compose
77
- extend Quo::Utilities::Sanitize
78
- extend Quo::Utilities::Wrap
79
-
80
- def self.call: (**untyped options) -> untyped
81
- def self.call!: (**untyped options) -> untyped
82
- def self.description: (?String) -> (String | nil)
83
- self.@description: String | nil
84
-
85
- @scope: ActiveRecord::Relation | nil
86
-
87
- attr_reader current_page: (Integer | nil)
88
- attr_reader page_size: (Integer | nil)
89
- attr_reader options: Hash[untyped, untyped]
90
-
91
- def initialize: (**untyped options) -> void
92
- def query: () -> composable
93
- def compose: (composable right, ?untyped? joins) -> Quo::MergedQuery
94
- alias + compose
95
-
96
- def copy: (**untyped options) -> query
97
-
98
- def limit: (untyped limit) -> query
99
- def order: (untyped options) -> query
100
- def group: (*untyped options) -> query
101
- def includes: (*untyped options) -> query
102
- def preload: (*untyped options) -> query
103
- def select: (*untyped options) -> query
104
-
105
- def sum: (?untyped column_name) -> Numeric
106
- def average: (untyped column_name) -> Numeric
107
- def minimum: (untyped column_name) -> Numeric
108
- def maximum: (untyped column_name) -> Numeric
109
- def count: () -> Integer
110
-
111
- alias total_count count
112
-
113
- alias size count
114
- def page_count: () -> Integer
115
- def first: (*untyped args) -> untyped
116
- def first!: (*untyped args) -> untyped
117
- def last: (*untyped args) -> untyped
118
- def to_a: () -> Array[untyped]
119
- def to_eager: (?::Hash[untyped, untyped] more_opts) -> Quo::EagerQuery
120
- alias load to_eager
121
- def enumerator: () -> Quo::Enumerator
122
-
123
- # Set a block used to transform data after query fetching
124
- def transform: () ?{ () -> untyped } -> self
125
-
126
- def exists?: () -> bool
127
- def none?: () -> bool
128
- alias empty? none?
129
- def relation?: () -> bool
130
- def eager?: () -> bool
131
- def paged?: () -> bool
132
-
133
- def model: () -> (untyped | nil)
134
- def klass: () -> (untyped | nil)
135
-
136
- def transform?: () -> bool
137
- def to_sql: () -> (String | nil)
138
- def unwrap: () -> query_like
139
-
140
- private
141
-
142
- def formatted_queries?: () -> bool
143
- def trim_query: (String sql) -> String
144
- def format_query: (String sql_str) -> String
145
- def transformer: () -> (nil | ^(untyped) -> untyped)
146
- def offset: () -> Integer
147
- def configured_query: () -> ActiveRecord::Relation
148
- def sanitised_page_size: () -> Integer
149
- def query_with_logging: () -> ActiveRecord::Relation
150
- def underlying_query: () -> ActiveRecord::Relation
151
- def unwrap_relation: (composable query) -> ActiveRecord::Relation
152
- def test_eager: (composable rel) -> bool
153
- def test_relation: (composable rel) -> bool
154
- end
155
-
156
- class MergedQuery < Quo::Query
157
- def initialize: (untyped options, ?untyped source_queries) -> void
158
-
159
- def query: () -> composable
160
-
161
- def to_s: () -> ::String
162
-
163
- private
12
+ type query = Quo::Query
13
+ type queryOrRel = query | ActiveRecord::Relation
14
+ # FIXME: anything that is Enumerable should be composable, but I don't know how to express that
15
+ type enumerable = Array[untyped] | Set[untyped]
16
+ type relOrEnumerable = ActiveRecord::Relation | enumerable
17
+ type composable = query | relOrEnumerable
164
18
 
165
- def source_queries_left: () -> composable
166
- def source_queries_right: () -> composable
167
- attr_reader source_queries: Array[composable]
168
- def operand_desc: (untyped operand) -> (nil | String)
19
+ interface _Logger
20
+ def info: (String) -> void
21
+ def error: (String) -> void
22
+ def debug: (String) -> void
169
23
  end
170
24
 
171
- class EagerQuery < Quo::Query
172
- def initialize: (**untyped options) -> void
173
- def query: () -> enumerable
174
- def relation?: () -> false
175
- def eager?: () -> true
176
- attr_reader collection: enumerable
177
-
178
- private
25
+ class Configuration
26
+ attr_accessor formatted_query_log: bool?
27
+ attr_accessor query_show_callstack_size: Integer?
28
+ attr_accessor logger: _Logger?
179
29
 
180
- def preload_includes: (untyped records, ?untyped? preload) -> untyped
30
+ def initialize: () -> void
181
31
  end
32
+ attr_reader self.configuration: Configuration
182
33
 
183
- class QueryComposer
184
- def initialize: (composable left, composable right, ?untyped? joins) -> void
185
- def compose: () -> Quo::MergedQuery
186
-
187
- private
188
-
189
- attr_reader left: composable
190
- attr_reader right: composable
191
- attr_reader joins: untyped
192
-
193
- def merge: () -> (ActiveRecord::Relation | Array[untyped] | void)
194
- def merged_options: () -> ::Hash[untyped, untyped]
195
- def unwrap_relation: (composable) -> query_like
196
- def relation_type?: (composable) -> bool
197
- def apply_joins: (ActiveRecord::Relation left_rel, untyped joins) -> ActiveRecord::Relation
198
- def both_relations?: (bool left_rel_type, bool right_rel_type) -> bool
199
- def left_relation_right_eager?: (bool left_rel_type, bool right_rel_type) -> bool
200
- def left_eager_right_relation?: (bool left_rel_type, bool right_rel_type) -> bool
201
- def both_eager_loaded?: (bool left_rel_type, bool right_rel_type) -> bool
202
-
203
- def raise_error: () -> void
204
- end
34
+ def self.configure: () { (Configuration config) -> void } -> void
205
35
  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.2.0
4
+ version: 0.3.1
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-20 00:00:00.000000000 Z
11
+ date: 2022-12-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -77,9 +77,20 @@ files:
77
77
  - lib/quo/utilities/sanitize.rb
78
78
  - lib/quo/utilities/wrap.rb
79
79
  - lib/quo/version.rb
80
+ - lib/quo/wrapped_query.rb
80
81
  - lib/tasks/quo.rake
81
82
  - rbs_collection.yaml
82
83
  - sig/quo.rbs
84
+ - sig/quo/eager_query.rbs
85
+ - sig/quo/enumerator.rbs
86
+ - sig/quo/merged_query.rbs
87
+ - sig/quo/query.rbs
88
+ - sig/quo/query_composer.rbs
89
+ - sig/quo/utilities/callstack.rbs
90
+ - sig/quo/utilities/compose.rbs
91
+ - sig/quo/utilities/sanitize.rbs
92
+ - sig/quo/utilities/wrap.rbs
93
+ - sig/quo/wrapped_query.rbs
83
94
  homepage: https://github.com/stevegeek/quo
84
95
  licenses:
85
96
  - MIT