graphiti_gql 0.2.26 → 0.2.29
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/Gemfile.lock +1 -1
- data/lib/graphiti_gql/engine.rb +11 -2
- data/lib/graphiti_gql/exception_handler.rb +52 -0
- 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 +177 -0
- data/lib/graphiti_gql/schema/fields/stats.rb +9 -6
- data/lib/graphiti_gql/schema/list_arguments.rb +2 -0
- data/lib/graphiti_gql/schema.rb +8 -0
- data/lib/graphiti_gql/version.rb +1 -1
- data/lib/graphiti_gql.rb +27 -3
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ade099acc586ef5902b1b30659ca47efed5cfb3e05e3fe1a778fa81b31b27528
|
|
4
|
+
data.tar.gz: 3a2226feab0dd284c3aeb832b30d90dc8165a9abc03fc40921aab47eece3d315
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 318d2eb2831f5d19bdcbdd9fbe6dd0a21fed8435875d9d4de0ca45b65b97515b5ca4f80afca282a5c1e11b85986133f5942ef4e96b21b4cb31ce492d35a07728
|
|
7
|
+
data.tar.gz: bc7b778005b056904a8fc4d3be767ee62a711f07fff533ddac833b96723abc5fc8368e9f63ecf2ddc40aee59544990939ff7d26a570a95ccc15ce2d8d5e93542
|
data/Gemfile.lock
CHANGED
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
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
module GraphitiGql
|
|
2
|
+
class ExceptionHandler
|
|
3
|
+
attr_reader :error, :context, :field
|
|
4
|
+
class_attribute :registry, :log, :notify, :default_message, :default_code
|
|
5
|
+
|
|
6
|
+
self.registry = {}
|
|
7
|
+
self.default_message = "We're sorry, something went wrong."
|
|
8
|
+
self.default_code = 500
|
|
9
|
+
|
|
10
|
+
def self.register_exception(err, opts)
|
|
11
|
+
registry[err] = opts
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
register_exception Graphiti::Errors::RecordNotFound, code: 404
|
|
15
|
+
register_exception Graphiti::Errors::SingularSideload, code: 400
|
|
16
|
+
register_exception Graphiti::Errors::InvalidAttributeAccess, code: 403
|
|
17
|
+
register_exception GraphitiGql::Errors::UnsupportedLast, code: 400
|
|
18
|
+
|
|
19
|
+
def initialize(err, obj, args, ctx, field)
|
|
20
|
+
@error = err
|
|
21
|
+
@obj = obj
|
|
22
|
+
@args = args
|
|
23
|
+
@context = ctx
|
|
24
|
+
@field = field
|
|
25
|
+
@config = get_config(err)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def notify
|
|
29
|
+
# noop
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def log
|
|
33
|
+
# noop
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def handle
|
|
37
|
+
notify if @config[:notify] != false
|
|
38
|
+
log if @config[:log] != false
|
|
39
|
+
|
|
40
|
+
message = @config[:message] ? err.message : default_message
|
|
41
|
+
code = @config[:code] || default_code
|
|
42
|
+
raise GraphQL::ExecutionError.new(message, extensions: { code: code })
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
private
|
|
46
|
+
|
|
47
|
+
def get_config(error)
|
|
48
|
+
registered = registry.find { |e, _| error.is_a?(e) }
|
|
49
|
+
registered ? registered[1] : {}
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
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,177 @@
|
|
|
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
|
+
stmt = "#{indent} #{num_results} #{"result".pluralize(num_results)}"
|
|
39
|
+
stmt << " of #{"type".pluralize(klasses.length)} #{klasses.to_sentence}" if num_results > 0
|
|
40
|
+
add_chunk(stmt, color, true)
|
|
41
|
+
|
|
42
|
+
took = ((stop - start) * 1000.0).round(2)
|
|
43
|
+
add_chunk("#{indent} Took: #{took}ms", :magenta, true)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def on_schema_before_execute(name, start, stop, id, payload)
|
|
47
|
+
Graphiti.debug(payload[:query].strip_heredoc, :white, true)
|
|
48
|
+
unless payload[:variables].empty?
|
|
49
|
+
Graphiti.debug("✨ Variables: #{payload[:variables].inspect}", :yellow, true)
|
|
50
|
+
end
|
|
51
|
+
unless payload[:context].empty?
|
|
52
|
+
Graphiti.debug("✨ Context: #{payload[:context].inspect}", :blue, true)
|
|
53
|
+
end
|
|
54
|
+
Graphiti.debug(%|💡 Debug tip! Override Resource#resolve:
|
|
55
|
+
|
|
56
|
+
class YourResource < ApplicationResource
|
|
57
|
+
# ... code ...
|
|
58
|
+
def resolve(scope)
|
|
59
|
+
debugger
|
|
60
|
+
# if activerecord, call scope.to_sql/scope.to_a
|
|
61
|
+
super
|
|
62
|
+
end
|
|
63
|
+
end|, :white, true)
|
|
64
|
+
Graphiti.debug("🤠🚀🤠🚀🤠🚀🤠🚀🤠🚀🤠🚀🤠🚀🤠 Executing! 🤠🚀🤠🚀🤠🚀🤠🚀🤠🚀🤠🚀🤠🚀🤠", :white, true)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def on_schema_execute(name, start, stop, id, payload)
|
|
68
|
+
if payload[:exception] || (response_errors = payload[:result]["errors"])
|
|
69
|
+
indent = indent(path: @last_association_path)
|
|
70
|
+
add_chunk("#{indent}❌🚨❌🚨❌🚨❌ ERROR! ❌🚨❌🚨❌🚨❌", :red, true, path: @last_association_path)
|
|
71
|
+
if @error_on_resolve
|
|
72
|
+
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.",
|
|
73
|
+
:red, true, path: @last_association_path)
|
|
74
|
+
end
|
|
75
|
+
flush_chunks(@chunks)
|
|
76
|
+
if response_errors
|
|
77
|
+
Graphiti.info("❌🚨 Response contained errors!", :red, true)
|
|
78
|
+
response_errors.each do |err|
|
|
79
|
+
Graphiti.info("#{err['extensions']['code']} - #{err['message']}", :red, true)
|
|
80
|
+
Graphiti.info("#{err['path'].join(".")}", :red, false) if err['path']
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
else
|
|
84
|
+
flush_chunks(@chunks)
|
|
85
|
+
took = ((stop - start) * 1000.0).round(2)
|
|
86
|
+
Graphiti.info("✅ Completed successfully in #{took}ms", :magenta, true)
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def on_resource_all(name, start, stop, id, payload)
|
|
91
|
+
@resolving = true
|
|
92
|
+
params = payload[:params].inspect
|
|
93
|
+
resource = payload[:resource].name
|
|
94
|
+
if thin_path.length == 1
|
|
95
|
+
add_chunk("Query.#{thin_path.first}", :yellow, true)
|
|
96
|
+
end
|
|
97
|
+
add_chunk("#{indent}\\_ #{resource}.all(#{params})", :cyan, true)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def on_association(name, start, stop, id, payload)
|
|
101
|
+
@last_association_path = thin_path
|
|
102
|
+
sideload = payload[:sideload]
|
|
103
|
+
add_chunk("#{indent}🔗 #{sideload.type} :#{sideload.name}", :white, true)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def on_before_stats(name, start, stop, id, payload)
|
|
107
|
+
@stats = true
|
|
108
|
+
add_chunk("#{indent}🔢 Calculating Statistics...", :yellow, true)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def on_after_stats(name, start, stop, id, payload)
|
|
112
|
+
@stats = false
|
|
113
|
+
took = ((stop - start) * 1000.0).round(2)
|
|
114
|
+
add_chunk("#{indent}🔢 Done! Took #{took}ms", :yellow, true)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def on_activerecord(name, start, stop, id, payload)
|
|
118
|
+
if @resolving || @stats
|
|
119
|
+
sql = payload[:sql]
|
|
120
|
+
unless sql.starts_with?('SHOW ')
|
|
121
|
+
add_chunk("#{indent}#{sql}", :blue, true)
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
private
|
|
127
|
+
|
|
128
|
+
def flush_chunks(chunks)
|
|
129
|
+
chunks.each_pair do |_, value|
|
|
130
|
+
value[:lines].each do |line|
|
|
131
|
+
Graphiti.info(line[:text], line[:color], line[:bold])
|
|
132
|
+
end
|
|
133
|
+
flush_chunks(value.except(:lines))
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def add_chunk(text, color, bold, path: nil)
|
|
138
|
+
path ||= thin_path
|
|
139
|
+
current_chunks = @chunks
|
|
140
|
+
path.each_with_index do |subpath, index|
|
|
141
|
+
last = index == path.length - 1
|
|
142
|
+
line = { text: text, color: color, bold: bold }
|
|
143
|
+
if current_chunks.key?(subpath)
|
|
144
|
+
if last
|
|
145
|
+
current_chunks[subpath][:lines] << line
|
|
146
|
+
else
|
|
147
|
+
current_chunks = current_chunks[subpath]
|
|
148
|
+
end
|
|
149
|
+
else
|
|
150
|
+
current_chunks[subpath] ||= { lines: [] }
|
|
151
|
+
current_chunks[subpath][:lines] << line
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def thin_path
|
|
157
|
+
path = Graphiti.context[:object][:current_path]
|
|
158
|
+
return [] unless path
|
|
159
|
+
path.reject do |p|
|
|
160
|
+
p.is_a?(Integer) ||
|
|
161
|
+
p == "nodes" ||
|
|
162
|
+
p == "node" ||
|
|
163
|
+
p == "edges"
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def indent(path: nil)
|
|
168
|
+
path ||= thin_path
|
|
169
|
+
" " * [path.length - 1, 0].max
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def current_path
|
|
173
|
+
path = Graphiti.context[:object][:current_path].join(".")
|
|
174
|
+
"Query.#{path}"
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
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
|
|
@@ -54,6 +54,8 @@ module GraphitiGql
|
|
|
54
54
|
end
|
|
55
55
|
end
|
|
56
56
|
@resource.filters.each_pair do |name, config|
|
|
57
|
+
next if config[:schema] == false
|
|
58
|
+
|
|
57
59
|
attr_type = generate_filter_attribute_type(type_name, name, config)
|
|
58
60
|
required = !!config[:required] || required_via_group.include?(name)
|
|
59
61
|
klass.argument name.to_s.camelize(:lower),
|
data/lib/graphiti_gql/schema.rb
CHANGED
|
@@ -101,6 +101,14 @@ module GraphitiGql
|
|
|
101
101
|
klass.connections.add(ResponseShim, Connection)
|
|
102
102
|
klass.connections.add(Array, ToManyConnection)
|
|
103
103
|
klass.orphan_types [GraphQL::Types::JSON]
|
|
104
|
+
klass.rescue_from(Exception) do |err, obj, args, ctx, field|
|
|
105
|
+
if GraphitiGql.config.error_handling
|
|
106
|
+
handler = GraphitiGql.config.exception_handler
|
|
107
|
+
handler.new(err, obj, args, ctx, field).handle
|
|
108
|
+
else
|
|
109
|
+
raise err
|
|
110
|
+
end
|
|
111
|
+
end
|
|
104
112
|
klass
|
|
105
113
|
end
|
|
106
114
|
end
|
data/lib/graphiti_gql/version.rb
CHANGED
data/lib/graphiti_gql.rb
CHANGED
|
@@ -27,13 +27,27 @@ require "graphiti_gql/schema/fields/to_one"
|
|
|
27
27
|
require "graphiti_gql/schema/fields/attribute"
|
|
28
28
|
require "graphiti_gql/schema/fields/stats"
|
|
29
29
|
require "graphiti_gql/active_resource"
|
|
30
|
+
require "graphiti_gql/exception_handler"
|
|
31
|
+
require "graphiti_gql/log_subscriber"
|
|
30
32
|
require "graphiti_gql/engine" if defined?(Rails)
|
|
31
33
|
|
|
32
34
|
module GraphitiGql
|
|
33
35
|
class Error < StandardError; end
|
|
34
36
|
|
|
35
37
|
class Configuration
|
|
36
|
-
attr_accessor :
|
|
38
|
+
attr_accessor :exception_handler, :error_handling, :logging
|
|
39
|
+
|
|
40
|
+
def exception_handler
|
|
41
|
+
@exception_handler ||= ExceptionHandler
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def error_handling
|
|
45
|
+
@error_handling != false
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def log
|
|
49
|
+
@log ||= !ENV['GRAPHITI_LOG_LEVEL'].nil?
|
|
50
|
+
end
|
|
37
51
|
end
|
|
38
52
|
|
|
39
53
|
def self.schema!
|
|
@@ -63,10 +77,20 @@ module GraphitiGql
|
|
|
63
77
|
context = Graphiti.context[:object]
|
|
64
78
|
end
|
|
65
79
|
Graphiti.with_context(context) do
|
|
66
|
-
|
|
80
|
+
payload = {
|
|
81
|
+
query: query_string,
|
|
67
82
|
variables: variables,
|
|
68
83
|
context: context
|
|
69
|
-
|
|
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
|
|
70
94
|
end
|
|
71
95
|
end
|
|
72
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.29
|
|
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
|
|
@@ -146,6 +146,7 @@ files:
|
|
|
146
146
|
- lib/graphiti_gql/active_resource.rb
|
|
147
147
|
- lib/graphiti_gql/engine.rb
|
|
148
148
|
- lib/graphiti_gql/errors.rb
|
|
149
|
+
- lib/graphiti_gql/exception_handler.rb
|
|
149
150
|
- lib/graphiti_gql/graphiti_hax.rb
|
|
150
151
|
- lib/graphiti_gql/loaders/belongs_to.rb
|
|
151
152
|
- lib/graphiti_gql/loaders/has_many.rb
|
|
@@ -153,6 +154,7 @@ files:
|
|
|
153
154
|
- lib/graphiti_gql/loaders/many.rb
|
|
154
155
|
- lib/graphiti_gql/loaders/many_to_many.rb
|
|
155
156
|
- lib/graphiti_gql/loaders/polymorphic_has_many.rb
|
|
157
|
+
- lib/graphiti_gql/log_subscriber.rb
|
|
156
158
|
- lib/graphiti_gql/response_shim.rb
|
|
157
159
|
- lib/graphiti_gql/schema.rb
|
|
158
160
|
- lib/graphiti_gql/schema/connection.rb
|