graphiti_gql 0.2.27 → 0.2.30

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: a02dc0813b461497979a165c77f9116922559c46a54ba26a5130e31832c4bcef
4
+ data.tar.gz: 60a27d5d31c31a39d062d1a65a2c0278ce3ea6f3cba3c4900ed1332525a54460
5
5
  SHA512:
6
- metadata.gz: 3879d099e79a23726bf32320d45a999dbfc4b6a7b2fe00982e330a6fc0ffb5cbe0c1940ae03dd18ef542eb26cf47ae9e14684a647dc21529a971e1986aef1184
7
- data.tar.gz: d985550be802a4206905cd4980fb5f6c434fb6aad517915602d67c6b7eb6efdab70ee8f699fe7b8dde6e97bc9bee36b5a081525505ae0c6a09aa9bbf84e97129
6
+ metadata.gz: e2a9a66b5dd624962bfffdc733115f8cf0363846db434bf9dfbe76374cd94dd0b9411ccf2aa93ce543a144ad0505e9f8d1e39bcb34b5593a7f870e17d7f13440
7
+ data.tar.gz: eb5004a261e6b7b815eb16ab548591c27beda1231e0875103c75d059c885ed2311b7d8c2b4d1a651d08905facdb8478b328eb5f78ec0fb812dab8cfc5f175583
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- graphiti_gql (0.2.27)
4
+ graphiti_gql (0.2.29)
5
5
  activemodel (> 6.0, < 8.0)
6
6
  graphiti (~> 1.3.9)
7
7
  graphql (~> 2.0)
@@ -37,18 +37,20 @@ module GraphitiGql
37
37
  def edge(name, node_id)
38
38
  found = @edges[name].empty? ? nil : @edges[name]
39
39
  if found && node_id
40
- found.find { |f| f.instance_variable_get(:@node_id) == node_id.to_s }
40
+ found.find do |f|
41
+ gql_node_id = f.instance_variable_get(:@node_id)
42
+ gql_node_id == node_id ||
43
+ gql_node_id == node_id.to_s ||
44
+ gql_node_id == @resource.gid(node_id)
45
+ end
41
46
  else
42
47
  found
43
48
  end
44
49
  end
45
50
 
46
- def decoded_id
47
- Base64.decode64(self.id)
48
- end
49
-
50
- def int_id
51
- decoded_id.to_i
51
+ def _id
52
+ deserialized = @resource.deserialize_gid(id)
53
+ deserialized.to_i.to_s == deserialized ? deserialized.to_i : deserialized
52
54
  end
53
55
  end
54
56
 
@@ -77,7 +79,7 @@ module GraphitiGql
77
79
  data # fire query
78
80
  Node.new(underscore(data[data.keys.first]), @resource)
79
81
  else
80
- nodes.find { |n| n.id == id.to_s }
82
+ nodes.find { |n| n.id == id.to_s || n.id == @resource.gid(id) }
81
83
  end
82
84
  end
83
85
 
@@ -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
@@ -71,13 +71,46 @@ module GraphitiGql
71
71
  end
72
72
 
73
73
  class_methods do
74
+ def gid(*ids)
75
+ ids = ids[0] if ids[0].is_a?(Array) && ids.length == 1
76
+ gids = ids.map { |id| serialize_gid(id) }
77
+ ids.length == 1 ? gids.first : gids
78
+ end
79
+
80
+ def serialize_gid(id)
81
+ Base64.encode64("#{graphql_name}/#{id}")
82
+ end
83
+
84
+ def deserialize_gid(gid, integer = true)
85
+ id = Base64.decode64(gid).split("/").last
86
+ id.to_i.to_s == id ? id.to_i : id
87
+ end
88
+
74
89
  def config
75
90
  return @config if @config
76
91
  super
77
92
  @config = @config.merge(value_objects: {}, is_value_object: false)
78
93
  end
79
94
 
95
+ def graphql_name
96
+ @graphql_name ||= begin
97
+ if name.nil?
98
+ 'Unknown'
99
+ else
100
+ name.gsub('Resource', '').gsub('::', '')
101
+ end
102
+ end
103
+ end
104
+
80
105
  def attribute(*args)
106
+ # new default is :gid, not integer_id
107
+ if args[0] == :id && args[1] == :integer_id
108
+ args[1] = :gid
109
+ opts = args.extract_options!
110
+ opts[:null] = false
111
+ args << opts
112
+ end
113
+
81
114
  super(*args).tap do
82
115
  opts = args.extract_options!
83
116
  att = config[:attributes][args[0]]
@@ -143,6 +176,12 @@ module GraphitiGql
143
176
  deprecation_reason: opts[:deprecation_reason]
144
177
  )
145
178
  end
179
+
180
+ def all(*args)
181
+ params = args[0]
182
+ Graphiti.broadcast("resource.all", { params: params, resource: self })
183
+ super
184
+ end
146
185
  end
147
186
  end
148
187
  Graphiti::Resource.send(:prepend, ResourceExtras)
@@ -314,6 +353,7 @@ module GraphitiGql
314
353
  description: 'Datetime with milliseconds'
315
354
  }
316
355
 
356
+ # Support ranges
317
357
  [:string, :integer, :float, :datetime, :precise_datetime].each do |kind|
318
358
  duped_hash = Graphiti::Util::Hash.deep_dup(Graphiti::Types[:hash])
319
359
  type = Graphiti::Types[:"#{kind}_range"] = duped_hash
@@ -328,6 +368,29 @@ module GraphitiGql
328
368
  }
329
369
  end
330
370
 
371
+ # Support gid
372
+ gid_going_out = ->(id) {
373
+ resource.gid(id)
374
+ }
375
+
376
+ gid_coming_in = definition.constructor do |input|
377
+ if defined?(ApplicationResource)
378
+ ApplicationResource.deserialize_gid(input)
379
+ else
380
+ Graphiti::Resource.deserialize_gid(input)
381
+ end
382
+ end
383
+
384
+ # Register it with Graphiti
385
+ Graphiti::Types[:gid] = {
386
+ params: gid_coming_in,
387
+ read: gid_going_out,
388
+ write: gid_coming_in,
389
+ kind: 'scalar',
390
+ canonical_name: :gid,
391
+ description: 'Globally-unique identifier',
392
+ }
393
+
331
394
  module ActiveRecordAdapterExtras
332
395
  extend ActiveSupport::Concern
333
396
 
@@ -338,6 +401,8 @@ module GraphitiGql
338
401
  alias_method :filter_precise_datetime_gte, :filter_gte
339
402
  alias_method :filter_precise_datetime_eq, :filter_eq
340
403
  alias_method :filter_precise_datetime_not_eq, :filter_not_eq
404
+ alias_method :filter_gid_eq, :filter_eq
405
+ alias_method :filter_gid_not_eq, :filter_not_eq
341
406
  end
342
407
 
343
408
  # TODO: integration specs mysql vs postgres for case sensitivity
@@ -387,11 +452,14 @@ module GraphitiGql
387
452
  class << self
388
453
  alias :old_default_operators :default_operators
389
454
  def default_operators
390
- old_default_operators.merge({
391
- precise_datetime: numerical_operators,
455
+ ops = old_default_operators.merge({
456
+ precise_datetime: numerical_operators - [:not_eq],
392
457
  string_enum: [:eq, :not_eq],
393
458
  integer_enum: [:eq, :not_eq],
459
+ gid: [:eq, :not_eq]
394
460
  })
461
+ ops[:datetime] = ops[:datetime] - [:not_eq]
462
+ ops
395
463
  end
396
464
  end
397
465
  end
@@ -519,4 +587,21 @@ class Graphiti::ValueObjectAssociation
519
587
  instance.parent = parent
520
588
  instance
521
589
  end
590
+ end
591
+
592
+ module Graphiti
593
+ def self.debug(msg, color = :white, bold = false)
594
+ log(msg, color, bold, level: :debug)
595
+ end
596
+
597
+ def self.info(msg, color = :white, bold = false)
598
+ log(msg, color, bold, level: :info)
599
+ end
600
+
601
+ def self.log(msg, color = :white, bold = false, level: nil)
602
+ return unless ::GraphitiGql.config.log
603
+ colored = ActiveSupport::LogSubscriber.new.send(:color, msg, color, bold)
604
+ level ||= :debug
605
+ logger.send(level, colored)
606
+ end
522
607
  end
@@ -1,6 +1,10 @@
1
1
  module GraphitiGql
2
2
  module Loaders
3
- class FakeRecord < Struct.new(:id, :type)
3
+ class FakeRecord < Struct.new(:id, :type, :graphiti_resource)
4
+ def initialize(*args)
5
+ super
6
+ @__graphiti_resource = graphiti_resource
7
+ end
4
8
  end
5
9
 
6
10
  class BelongsTo < GraphQL::Batch::Loader
@@ -10,6 +14,7 @@ module GraphitiGql
10
14
  end
11
15
 
12
16
  def perform(ids)
17
+ Graphiti.broadcast("association", { sideload: @sideload })
13
18
  # process nils
14
19
  ids.each { |id| fulfill(id, nil) if id.nil? }
15
20
  ids.compact!
@@ -20,11 +25,11 @@ module GraphitiGql
20
25
  ids.each do |id|
21
26
  child = @sideload.children.values.find { |c| c.group_name == id[:type].to_sym }
22
27
  type = Schema::Registry.instance.get(child.resource.class, interface: false)[:type]
23
- fulfill(id, FakeRecord.new(id[:id], type))
28
+ fulfill(id, FakeRecord.new(id[:id], type, child.resource))
24
29
  end
25
30
  else
26
31
  type = Schema::Registry.instance.get(@sideload.resource.class)[:type]
27
- ids.each { |id| fulfill(id, FakeRecord.new(id, type)) }
32
+ ids.each { |id| fulfill(id, FakeRecord.new(id, type, @sideload.resource)) }
28
33
  end
29
34
  return
30
35
  end
@@ -39,9 +44,10 @@ module GraphitiGql
39
44
  payload.each_pair do |key, value|
40
45
  params = { filter: {} }
41
46
  klass = @sideload.children.values.find { |c| c.group_name == key.to_sym }
42
- params = {
43
- filter: { id: { eq: value.join(",") } }
44
- }
47
+ filter_ids = value.map { |id| @sideload.resource.class.gid(id.to_s) }
48
+ params = @params.merge({
49
+ filter: { id: { eq: filter_ids } }
50
+ })
45
51
 
46
52
  futures << Concurrent::Future.execute do
47
53
  { type: key, data: klass.resource.class.all(params).data }
@@ -54,9 +60,10 @@ module GraphitiGql
54
60
  end
55
61
  else
56
62
  resource = Schema.registry.get(@sideload.resource.class)[:resource]
57
- params = {}
63
+ params = @params.deep_dup
58
64
  unless resource.singular
59
- params[:filter] = {id: { eq: ids.join(",") } }
65
+ filter_ids = ids.map { |id| @sideload.resource.class.gid(id.to_s) }
66
+ params[:filter] = {id: { eq: filter_ids } }
60
67
  end
61
68
  records = resource.all(params).data
62
69
  if resource.singular
@@ -15,10 +15,11 @@ module GraphitiGql
15
15
 
16
16
  def initialize(sideload, params)
17
17
  @sideload = sideload
18
- @params = params
18
+ @params = params.merge(typecast_filters: false)
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
 
@@ -33,6 +34,7 @@ module GraphitiGql
33
34
  pk
34
35
  end
35
36
  end
37
+ ids.compact!
36
38
 
37
39
  build_params(ids, parent_records)
38
40
  resource = Schema.registry.get(@sideload.resource.class)[:resource]
@@ -52,13 +54,16 @@ module GraphitiGql
52
54
  if @sideload.polymorphic_as
53
55
  type = ids[0][:"#{@sideload.polymorphic_as}_type"]
54
56
  foreign_keys = ids.map { |id| id[@sideload.foreign_key] }
57
+ foreign_keys.map! { |id| @sideload.parent_resource.class.gid(id) }
55
58
  @params[:filter][:"#{@sideload.polymorphic_as}_type"] = type
56
- @params[:filter][@sideload.foreign_key] = foreign_keys.join(",")
59
+ @params[:filter][@sideload.foreign_key] = foreign_keys
57
60
  elsif @sideload.type == :many_to_many
61
+ filter_ids = ids.map { |id| @sideload.parent_resource.class.gid(id) }
58
62
  fk = @sideload.foreign_key.values.first
59
- @params[:filter].merge!(fk => { eq: ids.join(",") })
63
+ @params[:filter].merge!(fk => { eq: filter_ids })
60
64
  elsif !@sideload.parent_resource.class.singular
61
- @params[:filter].merge!(@sideload.foreign_key => { eq: ids.join(",") })
65
+ filter_ids = ids.map { |id| @sideload.parent_resource.class.gid(id) }
66
+ @params[:filter].merge!(@sideload.foreign_key => { eq: filter_ids })
62
67
  end
63
68
 
64
69
  if @params[:stats]
@@ -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
@@ -37,7 +37,16 @@ module GraphitiGql
37
37
  end
38
38
  end
39
39
  return if value.nil?
40
- Graphiti::Types[_config[:type]][:read].call(value)
40
+
41
+ caster = Graphiti::Types[_config[:type]][:read]
42
+ # Dry::Types can't be instance_exec'd
43
+ # This dependency has probably served it's purpose and can be
44
+ # refactored away
45
+ if caster.is_a?(Proc)
46
+ instance_exec(value, &caster)
47
+ else
48
+ caster.call(value)
49
+ end
41
50
  end
42
51
  end
43
52
 
@@ -51,7 +60,6 @@ module GraphitiGql
51
60
  if !field_type
52
61
  canonical_graphiti_type = Graphiti::Types.name_for(@config[:type])
53
62
  field_type = GQL_TYPE_MAP[canonical_graphiti_type.to_sym]
54
- field_type = String if @name == :id
55
63
  end
56
64
  field_type = [field_type] if @config[:type].to_s.starts_with?("array_of")
57
65
  field_type
@@ -12,7 +12,7 @@ module GraphitiGql
12
12
  null: true,
13
13
  extras: [:lookahead]
14
14
  unless @registered[:resource].singular
15
- field.argument(:id, String, required: true)
15
+ field.argument(:id, GraphQL::Types::ID, required: true)
16
16
  end
17
17
  _registered = @registered
18
18
  query.define_method name do |**arguments|
@@ -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
@@ -77,7 +77,6 @@ module GraphitiGql
77
77
  canonical_graphiti_type = Graphiti::Types
78
78
  .name_for(filter_config[:type])
79
79
  type = GQL_TYPE_MAP[canonical_graphiti_type]
80
- type = String if filter_name == :id
81
80
  end
82
81
 
83
82
  if (allowlist = filter_config[:allow])
@@ -60,8 +60,7 @@ module GraphitiGql
60
60
  private
61
61
 
62
62
  def key_for_resource(resource)
63
- resource.graphql_name ||
64
- resource.name.gsub('Resource', '').gsub('::', '')
63
+ resource.graphql_name
65
64
  end
66
65
  end
67
66
  end
@@ -141,6 +141,17 @@ module GraphitiGql
141
141
  klass = Class.new(Schema.base_object)
142
142
  end
143
143
 
144
+ klass.define_method :resource do
145
+ return @resource if @resource
146
+ resource = object.instance_variable_get(:@__graphiti_resource)
147
+ resource_class = resource.class
148
+ if resource_class.polymorphic? && !resource_class.polymorphic_child?
149
+ resource_class = resource_class.resource_for_model(object)
150
+ end
151
+ @resource = resource_class
152
+ resource_class
153
+ end
154
+
144
155
  klass
145
156
  end
146
157
 
@@ -33,6 +33,7 @@ module GraphitiGql
33
33
  integer_id: String,
34
34
  string: String,
35
35
  uuid: String,
36
+ gid: GraphQL::Types::ID,
36
37
  integer: Integer,
37
38
  big_integer: GraphQL::Types::BigInt,
38
39
  float: Float,
@@ -68,7 +69,9 @@ module GraphitiGql
68
69
  end
69
70
 
70
71
  def self.base_object
72
+ return @base_object if @base_object
71
73
  klass = Class.new(GraphQL::Schema::Object)
74
+
72
75
  # TODO make this config maybe
73
76
  if defined?(ActionView)
74
77
  klass.send(:include, ActionView::Helpers::TranslationHelper)
@@ -79,6 +82,7 @@ module GraphitiGql
79
82
  end
80
83
  end
81
84
  end
85
+ @base_object = klass
82
86
  klass
83
87
  end
84
88
 
@@ -74,6 +74,9 @@ module GraphitiGql
74
74
  resource.gql(params.merge(fields: fields), ctx, q, opts)
75
75
  end
76
76
 
77
+ def gid(*ids)
78
+ resource.gid(*ids)
79
+ end
77
80
 
78
81
  def run
79
82
  lambda do
@@ -1,3 +1,3 @@
1
1
  module GraphitiGql
2
- VERSION = "0.2.27"
2
+ VERSION = "0.2.30"
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.30
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-31 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