graphiti_gql 0.2.27 → 0.2.28

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: 8f6c4549cfff9295d8c6736efb65d443c8f189ca8c333b70ba24a764fa689b53
4
- data.tar.gz: 71f1989c21eb48dde565f6523f798c8bd66080b572a51a00579768d29a1e87b9
3
+ metadata.gz: ffc7f76831ea15375482b1ec32d6fe090b19c9ebdac1ea081805dfcf32497072
4
+ data.tar.gz: 3ac75bdef55c8cf63de7e2f9554dbc0e58f1f5a7a23ba591cbfac9891a9b8118
5
5
  SHA512:
6
- metadata.gz: 3879d099e79a23726bf32320d45a999dbfc4b6a7b2fe00982e330a6fc0ffb5cbe0c1940ae03dd18ef542eb26cf47ae9e14684a647dc21529a971e1986aef1184
7
- data.tar.gz: d985550be802a4206905cd4980fb5f6c434fb6aad517915602d67c6b7eb6efdab70ee8f699fe7b8dde6e97bc9bee36b5a081525505ae0c6a09aa9bbf84e97129
6
+ metadata.gz: e51aca16a756ed7f0e053fda559e07831433ae0e37a6ab40908468a07bfa93eb48c12abd045ea93dbdc8dc8b716ff5abb190347b88d089b13305d2fd7a6ac818
7
+ data.tar.gz: 53e611a009a2277cfc0bc7318710a537fd02c06760921716e149bfa8cebbbeb3607c3b409e8830460be1e80ba41b66c366507f1057c2215ee7fb7ffc79b77653
@@ -2,11 +2,20 @@ module GraphitiGql
2
2
  class Engine < ::Rails::Engine
3
3
  isolate_namespace GraphitiGql
4
4
 
5
- # TODO improvable?
6
5
  config.to_prepare do
7
- # initializer "graphiti_gql.generate_schema" do
8
6
  Dir.glob("#{Rails.root}/app/resources/**/*").each { |f| require(f) }
9
7
  GraphitiGql.schema!
8
+
9
+ log_level = ENV.fetch('GRAPHITI_LOG_LEVEL', '1').to_i
10
+ log_activerecord = false
11
+ if log_level == -1 && defined?(ActiveRecord)
12
+ log_level = 0
13
+ log_activerecord = true
14
+ end
15
+ Graphiti.logger.level = log_level
16
+ if GraphitiGql.config.log
17
+ GraphitiGql::LogSubscriber.subscribe!(activerecord: log_activerecord)
18
+ end
10
19
  end
11
20
  end
12
21
  end
@@ -143,6 +143,12 @@ module GraphitiGql
143
143
  deprecation_reason: opts[:deprecation_reason]
144
144
  )
145
145
  end
146
+
147
+ def all(*args)
148
+ params = args[0]
149
+ Graphiti.broadcast("resource.all", { params: params, resource: self })
150
+ super
151
+ end
146
152
  end
147
153
  end
148
154
  Graphiti::Resource.send(:prepend, ResourceExtras)
@@ -519,4 +525,21 @@ class Graphiti::ValueObjectAssociation
519
525
  instance.parent = parent
520
526
  instance
521
527
  end
528
+ end
529
+
530
+ module Graphiti
531
+ def self.debug(msg, color = :white, bold = false)
532
+ log(msg, color, bold, level: :debug)
533
+ end
534
+
535
+ def self.info(msg, color = :white, bold = false)
536
+ log(msg, color, bold, level: :info)
537
+ end
538
+
539
+ def self.log(msg, color = :white, bold = false, level: nil)
540
+ return unless ::GraphitiGql.config.log
541
+ colored = ActiveSupport::LogSubscriber.new.send(:color, msg, color, bold)
542
+ level ||= :debug
543
+ logger.send(level, colored)
544
+ end
522
545
  end
@@ -10,6 +10,7 @@ module GraphitiGql
10
10
  end
11
11
 
12
12
  def perform(ids)
13
+ Graphiti.broadcast("association", { sideload: @sideload })
13
14
  # process nils
14
15
  ids.each { |id| fulfill(id, nil) if id.nil? }
15
16
  ids.compact!
@@ -19,6 +19,7 @@ module GraphitiGql
19
19
  end
20
20
 
21
21
  def perform(parent_records)
22
+ Graphiti.broadcast("association", { sideload: @sideload })
22
23
  raise ::Graphiti::Errors::UnsupportedPagination if paginating? && parent_records.length > 1
23
24
  raise Errors::UnsupportedStats if requesting_stats? && parent_records.length > 1 && !can_group?
24
25
 
@@ -0,0 +1,174 @@
1
+ # TODO: remove OG graphiti debugger
2
+ module GraphitiGql
3
+ class LogSubscriber
4
+ def self.subscribe!(activerecord: false)
5
+ instance = LogSubscriber.new
6
+ instance.subscribe!('resolve', :on_data)
7
+ instance.subscribe!('schema.before_execute', :on_schema_before_execute)
8
+ instance.subscribe!('schema.execute', :on_schema_execute)
9
+ instance.subscribe!('resource.all', :on_resource_all)
10
+ instance.subscribe!('association', :on_association)
11
+ instance.subscribe!('before_stats', :on_before_stats)
12
+ instance.subscribe!('after_stats', :on_after_stats)
13
+ if activerecord
14
+ ActiveSupport::Notifications
15
+ .subscribe("sql.active_record", instance.method(:on_activerecord))
16
+ end
17
+ end
18
+
19
+ def initialize
20
+ @chunks = {}
21
+ end
22
+
23
+ def subscribe!(name, method_name)
24
+ ActiveSupport::Notifications
25
+ .subscribe("#{name}.graphiti", method(method_name))
26
+ end
27
+
28
+ def on_data(name, start, stop, id, payload)
29
+ @resolving = false
30
+ if payload[:exception]
31
+ @error_on_resolve = true
32
+ return
33
+ end
34
+
35
+ num_results = payload[:results].length
36
+ klasses = payload[:results].map(&:class).map(&:name).uniq
37
+ color = num_results == 0 ? :yellow : :green
38
+ add_chunk("#{indent} #{num_results} #{"result".pluralize(num_results)} of #{"type".pluralize(klasses.length)} #{klasses.to_sentence}", color, true)
39
+
40
+ took = ((stop - start) * 1000.0).round(2)
41
+ add_chunk("#{indent} Took: #{took}ms", :magenta, true)
42
+ end
43
+
44
+ def on_schema_before_execute(name, start, stop, id, payload)
45
+ Graphiti.debug(payload[:query].strip_heredoc, :white, true)
46
+ unless payload[:variables].empty?
47
+ Graphiti.debug("✨ Variables: #{payload[:variables].inspect}", :yellow, true)
48
+ end
49
+ unless payload[:context].empty?
50
+ Graphiti.debug("✨ Context: #{payload[:context].inspect}", :blue, true)
51
+ end
52
+ Graphiti.debug(%|💡 Debug tip! Override Resource#resolve:
53
+
54
+ class YourResource < ApplicationResource
55
+ # ... code ...
56
+ def resolve(scope)
57
+ debugger
58
+ # if activerecord, call scope.to_sql/scope.to_a
59
+ super
60
+ end
61
+ end|, :white, true)
62
+ Graphiti.debug("🤠🚀🤠🚀🤠🚀🤠🚀🤠🚀🤠🚀🤠🚀🤠 Executing! 🤠🚀🤠🚀🤠🚀🤠🚀🤠🚀🤠🚀🤠🚀🤠", :white, true)
63
+ end
64
+
65
+ def on_schema_execute(name, start, stop, id, payload)
66
+ if payload[:exception] || (response_errors = payload[:result]["errors"])
67
+ indent = indent(path: @last_association_path)
68
+ add_chunk("#{indent}❌🚨❌🚨❌🚨❌ ERROR! ❌🚨❌🚨❌🚨❌", :red, true, path: @last_association_path)
69
+ if @error_on_resolve
70
+ add_chunk("#{indent}This error occurred while executing the above query, so it's likely not caused by Graphiti itself. Maybe bad SQL? Try running again and putting a debugger in this Resource's #resolve, or try to run the query independent of Graphiti/GraphQL.",
71
+ :red, true, path: @last_association_path)
72
+ end
73
+ flush_chunks(@chunks)
74
+ if response_errors
75
+ Graphiti.info("❌🚨 Response contained errors!", :red, true)
76
+ response_errors.each do |err|
77
+ Graphiti.info("#{err['extensions']['code']} - #{err['message']}", :red, true)
78
+ Graphiti.info("#{err['path'].join(".")}", :red, false)
79
+ end
80
+ end
81
+ else
82
+ flush_chunks(@chunks)
83
+ took = ((stop - start) * 1000.0).round(2)
84
+ Graphiti.info("✅ Completed successfully in #{took}ms", :magenta, true)
85
+ end
86
+ end
87
+
88
+ def on_resource_all(name, start, stop, id, payload)
89
+ @resolving = true
90
+ params = payload[:params].inspect
91
+ resource = payload[:resource].name
92
+ if thin_path.length == 1
93
+ add_chunk("Query.#{thin_path.first}", :yellow, true)
94
+ end
95
+ add_chunk("#{indent}\\_ #{resource}.all(#{params})", :cyan, true)
96
+ end
97
+
98
+ def on_association(name, start, stop, id, payload)
99
+ @last_association_path = thin_path
100
+ sideload = payload[:sideload]
101
+ add_chunk("#{indent}🔗 #{sideload.type} :#{sideload.name}", :white, true)
102
+ end
103
+
104
+ def on_before_stats(name, start, stop, id, payload)
105
+ @stats = true
106
+ add_chunk("#{indent}🔢 Calculating Statistics...", :yellow, true)
107
+ end
108
+
109
+ def on_after_stats(name, start, stop, id, payload)
110
+ @stats = false
111
+ took = ((stop - start) * 1000.0).round(2)
112
+ add_chunk("#{indent}🔢 Done! Took #{took}ms", :yellow, true)
113
+ end
114
+
115
+ def on_activerecord(name, start, stop, id, payload)
116
+ if @resolving || @stats
117
+ sql = payload[:sql]
118
+ unless sql.starts_with?('SHOW ')
119
+ add_chunk("#{indent}#{sql}", :blue, true)
120
+ end
121
+ end
122
+ end
123
+
124
+ private
125
+
126
+ def flush_chunks(chunks)
127
+ chunks.each_pair do |_, value|
128
+ value[:lines].each do |line|
129
+ Graphiti.info(line[:text], line[:color], line[:bold])
130
+ end
131
+ flush_chunks(value.except(:lines))
132
+ end
133
+ end
134
+
135
+ def add_chunk(text, color, bold, path: nil)
136
+ path ||= thin_path
137
+ current_chunks = @chunks
138
+ path.each_with_index do |subpath, index|
139
+ last = index == path.length - 1
140
+ line = { text: text, color: color, bold: bold }
141
+ if current_chunks.key?(subpath)
142
+ if last
143
+ current_chunks[subpath][:lines] << line
144
+ else
145
+ current_chunks = current_chunks[subpath]
146
+ end
147
+ else
148
+ current_chunks[subpath] ||= { lines: [] }
149
+ current_chunks[subpath][:lines] << line
150
+ end
151
+ end
152
+ end
153
+
154
+ def thin_path
155
+ path = Graphiti.context[:object][:current_path]
156
+ path.reject do |p|
157
+ p.is_a?(Integer) ||
158
+ p == "nodes" ||
159
+ p == "node" ||
160
+ p == "edges"
161
+ end
162
+ end
163
+
164
+ def indent(path: nil)
165
+ path ||= thin_path
166
+ " " * [path.length - 1, 0].max
167
+ end
168
+
169
+ def current_path
170
+ path = Graphiti.context[:object][:current_path].join(".")
171
+ "Query.#{path}"
172
+ end
173
+ end
174
+ end
@@ -9,16 +9,19 @@ module GraphitiGql
9
9
  def apply(type)
10
10
  type.field :stats, build_stat_class, null: false
11
11
  type.define_method :stats do
12
+ Graphiti.broadcast('before_stats', {})
12
13
  # Process grouped (to-many relationship) stats
13
- stats = object.proxy.stats.deep_dup
14
- stats.each_pair do |attr, calc|
15
- calc.each_pair do |calc_name, value|
16
- if value.is_a?(Hash)
17
- stats[attr][calc_name] = value[parent.id]
14
+ Graphiti.broadcast('after_stats', {}) do
15
+ stats = object.proxy.stats.deep_dup
16
+ stats.each_pair do |attr, calc|
17
+ calc.each_pair do |calc_name, value|
18
+ if value.is_a?(Hash)
19
+ stats[attr][calc_name] = value[parent.id]
20
+ end
18
21
  end
19
22
  end
23
+ stats
20
24
  end
21
- stats
22
25
  end
23
26
  type
24
27
  end
@@ -1,3 +1,3 @@
1
1
  module GraphitiGql
2
- VERSION = "0.2.27"
2
+ VERSION = "0.2.28"
3
3
  end
data/lib/graphiti_gql.rb CHANGED
@@ -28,13 +28,14 @@ require "graphiti_gql/schema/fields/attribute"
28
28
  require "graphiti_gql/schema/fields/stats"
29
29
  require "graphiti_gql/active_resource"
30
30
  require "graphiti_gql/exception_handler"
31
+ require "graphiti_gql/log_subscriber"
31
32
  require "graphiti_gql/engine" if defined?(Rails)
32
33
 
33
34
  module GraphitiGql
34
35
  class Error < StandardError; end
35
36
 
36
37
  class Configuration
37
- attr_accessor :exception_handler, :error_handling
38
+ attr_accessor :exception_handler, :error_handling, :logging
38
39
 
39
40
  def exception_handler
40
41
  @exception_handler ||= ExceptionHandler
@@ -43,6 +44,10 @@ module GraphitiGql
43
44
  def error_handling
44
45
  @error_handling != false
45
46
  end
47
+
48
+ def log
49
+ @log ||= !ENV['GRAPHITI_LOG_LEVEL'].nil?
50
+ end
46
51
  end
47
52
 
48
53
  def self.schema!
@@ -72,10 +77,20 @@ module GraphitiGql
72
77
  context = Graphiti.context[:object]
73
78
  end
74
79
  Graphiti.with_context(context) do
75
- result = schema.execute query_string,
80
+ payload = {
81
+ query: query_string,
76
82
  variables: variables,
77
83
  context: context
78
- result.to_h
84
+ }
85
+ Graphiti.broadcast("schema.before_execute", payload)
86
+ Graphiti.broadcast("schema.execute", payload) do
87
+ result = schema.execute query_string,
88
+ variables: variables,
89
+ context: context
90
+ result_hash = result.to_h
91
+ payload[:result] = result_hash
92
+ result_hash
93
+ end
79
94
  end
80
95
  end
81
96
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graphiti_gql
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.27
4
+ version: 0.2.28
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lee Richmond
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-08-22 00:00:00.000000000 Z
11
+ date: 2022-08-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: graphql
@@ -154,6 +154,7 @@ files:
154
154
  - lib/graphiti_gql/loaders/many.rb
155
155
  - lib/graphiti_gql/loaders/many_to_many.rb
156
156
  - lib/graphiti_gql/loaders/polymorphic_has_many.rb
157
+ - lib/graphiti_gql/log_subscriber.rb
157
158
  - lib/graphiti_gql/response_shim.rb
158
159
  - lib/graphiti_gql/schema.rb
159
160
  - lib/graphiti_gql/schema/connection.rb