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 +4 -4
- data/lib/graphiti_gql/engine.rb +11 -2
- data/lib/graphiti_gql/graphiti_hax.rb +23 -0
- data/lib/graphiti_gql/loaders/belongs_to.rb +1 -0
- data/lib/graphiti_gql/loaders/many.rb +1 -0
- data/lib/graphiti_gql/log_subscriber.rb +174 -0
- data/lib/graphiti_gql/schema/fields/stats.rb +9 -6
- data/lib/graphiti_gql/version.rb +1 -1
- data/lib/graphiti_gql.rb +18 -3
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ffc7f76831ea15375482b1ec32d6fe090b19c9ebdac1ea081805dfcf32497072
|
|
4
|
+
data.tar.gz: 3ac75bdef55c8cf63de7e2f9554dbc0e58f1f5a7a23ba591cbfac9891a9b8118
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e51aca16a756ed7f0e053fda559e07831433ae0e37a6ab40908468a07bfa93eb48c12abd045ea93dbdc8dc8b716ff5abb190347b88d089b13305d2fd7a6ac818
|
|
7
|
+
data.tar.gz: 53e611a009a2277cfc0bc7318710a537fd02c06760921716e149bfa8cebbbeb3607c3b409e8830460be1e80ba41b66c366507f1057c2215ee7fb7ffc79b77653
|
data/lib/graphiti_gql/engine.rb
CHANGED
|
@@ -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
|
|
@@ -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
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
data/lib/graphiti_gql/version.rb
CHANGED
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
|
-
|
|
80
|
+
payload = {
|
|
81
|
+
query: query_string,
|
|
76
82
|
variables: variables,
|
|
77
83
|
context: context
|
|
78
|
-
|
|
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.
|
|
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-
|
|
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
|