graphiti_gql 0.2.20 → 0.2.23

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 17c54a15f86e3855f814dcea6a7093ceb0b0252de6685c57017a19f3c83160db
4
- data.tar.gz: e0f018dbe747eaa43401f3f02ef77a526e3f5f2a0dad8964dd138bc083a38ad6
3
+ metadata.gz: c5dfc016180ec5fd536f236be63b24cad42471a74d44ab234dee1966f2de942e
4
+ data.tar.gz: f97bbe243fa4a205004abdbd522942005b09e87fa37ba1db465000b383e355d0
5
5
  SHA512:
6
- metadata.gz: b863f5de471a4991d28f35c544567cf7420b78852c202c527b79399deb7e67f7c03e4f539cd628e9827354670e259ba44a8762191aaa88a97e3c474d753ff0de
7
- data.tar.gz: e857d78632c3055263d4ae6287ab30836752c28cdd41836f411a82f4b64119b1420a79447c5a042c2829d24b57eec040d14a1eb9d2705aacc70935612ce5d5f8
6
+ metadata.gz: '08c76642c2b6be4401a6efcce4c9070c52eee1661c333bcefc30a328826a0558aa6ed013028cb4d173bb2b47565aeeda18c2648a946d6ebe1dbcde2147325ced'
7
+ data.tar.gz: d16a38a32815b6df020817bb5797ac26ce6507a443375955aad3c2c1fe8fe29192dbf0f01a854d6d565946daae1fe9a713c67df050bbc230c320c282a35e339f
data/Gemfile.lock CHANGED
@@ -1,7 +1,8 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- graphiti_gql (0.2.18)
4
+ graphiti_gql (0.2.23)
5
+ activemodel (> 6.0, < 8.0)
5
6
  graphiti (~> 1.3.9)
6
7
  graphql (~> 2.0)
7
8
  graphql-batch (~> 0.5)
@@ -47,13 +48,13 @@ GEM
47
48
  graphql-batch (0.5.1)
48
49
  graphql (>= 1.10, < 3)
49
50
  promise.rb (~> 0.7.2)
50
- i18n (1.10.0)
51
+ i18n (1.12.0)
51
52
  concurrent-ruby (~> 1.0)
52
53
  jsonapi-renderer (0.2.2)
53
54
  jsonapi-serializable (0.3.1)
54
55
  jsonapi-renderer (~> 0.2.0)
55
56
  method_source (1.0.0)
56
- minitest (5.15.0)
57
+ minitest (5.16.2)
57
58
  promise.rb (0.7.4)
58
59
  pry (0.13.1)
59
60
  coderay (~> 1.1)
@@ -75,14 +76,13 @@ GEM
75
76
  diff-lcs (>= 1.2.0, < 2.0)
76
77
  rspec-support (~> 3.11.0)
77
78
  rspec-support (3.11.0)
78
- tzinfo (2.0.4)
79
+ tzinfo (2.0.5)
79
80
  concurrent-ruby (~> 1.0)
80
81
 
81
82
  PLATFORMS
82
83
  arm64-darwin-21
83
84
 
84
85
  DEPENDENCIES
85
- activemodel (~> 7.0)
86
86
  bundler (~> 2.3)
87
87
  graphiti_gql!
88
88
  pry
data/graphiti_gql.gemspec CHANGED
@@ -38,9 +38,9 @@ Gem::Specification.new do |spec|
38
38
  spec.add_dependency "graphql", "~> 2.0"
39
39
  spec.add_dependency "graphql-batch", "~> 0.5"
40
40
  spec.add_dependency "graphiti", "~> 1.3.9"
41
+ spec.add_dependency "activemodel", ["> 6.0", "< 8.0"]
41
42
 
42
43
  spec.add_development_dependency "bundler", "~> 2.3"
43
44
  spec.add_development_dependency "rake", "~> 10.0"
44
45
  spec.add_development_dependency "rspec", "~> 3.0"
45
- spec.add_development_dependency "activemodel", "~> 7.0"
46
46
  end
@@ -74,6 +74,7 @@ module GraphitiGql
74
74
 
75
75
  def node(id = nil)
76
76
  if @resource.singular
77
+ data # fire query
77
78
  Node.new(underscore(data[data.keys.first]), @resource)
78
79
  else
79
80
  nodes.find { |n| n.id == id.to_s }
@@ -16,7 +16,10 @@ module GraphitiGql
16
16
  module ResourceExtras
17
17
  extend ActiveSupport::Concern
18
18
 
19
- included do
19
+ prepended do
20
+ extend ActiveModel::Callbacks
21
+ define_model_callbacks :query
22
+
20
23
  class << self
21
24
  attr_accessor :graphql_name, :singular
22
25
  end
@@ -57,7 +60,14 @@ module GraphitiGql
57
60
  @selections
58
61
  end
59
62
 
63
+ def around_scoping(original_scope, query_hash)
64
+ run_callbacks :query do
65
+ super { |scope| yield scope }
66
+ end
67
+ end
68
+
60
69
  class_methods do
70
+
61
71
  def attribute(*args)
62
72
  super(*args).tap do
63
73
  opts = args.extract_options!
@@ -85,7 +95,7 @@ module GraphitiGql
85
95
  end
86
96
  end
87
97
  end
88
- Graphiti::Resource.send(:include, ResourceExtras)
98
+ Graphiti::Resource.send(:prepend, ResourceExtras)
89
99
 
90
100
  module FilterExtras
91
101
  def filter_param
@@ -186,26 +196,14 @@ module GraphitiGql
186
196
  module ManyToManyExtras
187
197
  def self.prepended(klass)
188
198
  klass.class_eval do
189
- attr_reader :join_table_alias, :edge_magic
190
-
191
- class << self
192
- attr_reader :edge_resource
193
-
194
- def attribute(*args, &blk)
195
- @edge_resource ||= Class.new(Graphiti::Resource) do
196
- def self.abstract_class?
197
- true
198
- end
199
- end
200
- @edge_resource.attribute(*args, &blk)
201
- end
202
- end
199
+ attr_reader :join_table_alias, :edge_magic, :edge_resource
203
200
  end
204
201
  end
205
202
 
206
203
  def initialize(name, opts = {})
207
204
  @join_table_alias = opts[:join_table_alias]
208
205
  @edge_magic = opts[:edge_magic] == false ? false : true
206
+ @edge_resource = opts[:edge_resource]
209
207
  super
210
208
  end
211
209
 
@@ -269,7 +267,7 @@ module GraphitiGql
269
267
  module ActiveRecordAdapterExtras
270
268
  extend ActiveSupport::Concern
271
269
 
272
- included do
270
+ prepended do
273
271
  alias_method :filter_precise_datetime_lt, :filter_lt
274
272
  alias_method :filter_precise_datetime_lte, :filter_lte
275
273
  alias_method :filter_precise_datetime_gt, :filter_gt
@@ -277,16 +275,59 @@ module GraphitiGql
277
275
  alias_method :filter_precise_datetime_eq, :filter_eq
278
276
  alias_method :filter_precise_datetime_not_eq, :filter_not_eq
279
277
  end
278
+
279
+ # TODO: integration specs mysql vs postgres for case sensitivity
280
+ def mysql?(scope)
281
+ mysql = ActiveRecord::ConnectionAdapters::Mysql2Adapter
282
+ scope.model.connection.is_a?(mysql)
283
+ end
284
+
285
+ def filter_string_eq(scope, attribute, value, is_not: false)
286
+ if mysql?(scope)
287
+ clause = { attribute => value }
288
+ is_not ? scope.where.not(clause) : scope.where(clause)
289
+ else
290
+ # og behavior
291
+ column = column_for(scope, attribute)
292
+ clause = column.lower.eq_any(value.map(&:downcase))
293
+ end
294
+ end
295
+
296
+ def filter_string_eql(scope, attribute, value, is_not: false)
297
+ if mysql?(scope)
298
+ value = "BINARY #{value}"
299
+ end
300
+ # og behavior
301
+ clause = {attribute => value}
302
+ is_not ? scope.where.not(clause) : scope.where(clause)
303
+ end
304
+
305
+ def sanitized_like_for(scope, attribute, value, &block)
306
+ escape_char = "\\"
307
+ column = column_for(scope, attribute)
308
+ map = value.map { |v|
309
+ v = v.downcase unless mysql?(scope)
310
+ v = Sanitizer.sanitize_like(v, escape_char)
311
+ block.call v
312
+ }
313
+ arel = column
314
+ arel = arel.lower unless mysql?(scope)
315
+ arel.matches_any(map, escape_char, true)
316
+ end
280
317
  end
281
318
  if defined?(Graphiti::Adapters::ActiveRecord)
282
- Graphiti::Adapters::ActiveRecord.send(:include, ActiveRecordAdapterExtras)
319
+ Graphiti::Adapters::ActiveRecord.send(:prepend, ActiveRecordAdapterExtras)
283
320
  end
284
321
 
285
322
  Graphiti::Adapters::Abstract.class_eval do
286
323
  class << self
287
324
  alias :old_default_operators :default_operators
288
325
  def default_operators
289
- old_default_operators.merge(precise_datetime: numerical_operators)
326
+ old_default_operators.merge({
327
+ precise_datetime: numerical_operators,
328
+ string_enum: [:eq, :not_eq],
329
+ integer_enum: [:eq, :not_eq],
330
+ })
290
331
  end
291
332
  end
292
333
  end
@@ -16,13 +16,15 @@ module GraphitiGql
16
16
 
17
17
  private
18
18
 
19
+ def thru_model
20
+ thru = @sideload.foreign_key.keys.first
21
+ reflection = @sideload.parent_resource.model.reflect_on_association(thru)
22
+ reflection.klass
23
+ end
24
+
19
25
  def add_join_table_magic(proxy)
20
26
  return unless @sideload.edge_magic
21
27
  if defined?(ActiveRecord) && proxy.resource.model.ancestors.include?(ActiveRecord::Base)
22
- thru = @sideload.foreign_key.keys.first
23
- reflection = @sideload.parent_resource.model.reflect_on_association(thru)
24
- thru_model = reflection.klass
25
-
26
28
  thru_table_name = @sideload.join_table_alias || thru_model.table_name
27
29
  names = thru_model.column_names.map do |n|
28
30
  next if n == :id
@@ -3,12 +3,11 @@ module GraphitiGql
3
3
  module Fields
4
4
  class Attribute
5
5
  # If sideload is present, we're applying m2m metadata to an edge
6
- def initialize(resource, name, config, sideload = nil)
6
+ def initialize(resource, name, config)
7
7
  @resource = resource
8
8
  @config = config
9
9
  @name = name
10
10
  @alias = config[:alias]
11
- @sideload = sideload # is_edge: true
12
11
  end
13
12
 
14
13
  def apply(type)
@@ -16,13 +15,11 @@ module GraphitiGql
16
15
  _config = @config
17
16
  _name = @name
18
17
  _alias = @alias
19
- _sideload = @sideload
20
18
  opts = @config.slice(:null, :deprecation_reason)
21
19
  type.field(_name, field_type, **opts)
22
20
  type.define_method _name do
23
21
  if (readable = _config[:readable]).is_a?(Symbol)
24
22
  obj = object
25
- obj = object.node if _sideload
26
23
  resource = obj.instance_variable_get(:@__graphiti_resource)
27
24
  unless resource.send(readable)
28
25
  path = Graphiti.context[:object][:current_path].join(".")
@@ -30,25 +27,10 @@ module GraphitiGql
30
27
  end
31
28
  end
32
29
 
33
- edge_attrs = nil
34
- if _sideload
35
- edge_attrs = object.node.attributes
36
- .select { |k, v| k.to_s.starts_with?("_edge_") }
37
- edge_attrs.transform_keys! { |k| k.to_s.gsub("_edge_", "").to_sym }
38
- end
39
-
40
30
  value = if _config[:proc]
41
- if _sideload
42
- instance_exec(edge_attrs, object.node, &_config[:proc])
43
- else
44
- instance_eval(&_config[:proc])
45
- end
31
+ instance_eval(&_config[:proc])
46
32
  else
47
- if _sideload
48
- edge_attrs[_alias || _name]
49
- else
50
- object.send(_alias || _name)
51
- end
33
+ object.send(_alias || _name)
52
34
  end
53
35
  return if value.nil?
54
36
  Graphiti::Types[_config[:type]][:read].call(value)
@@ -35,7 +35,7 @@ module GraphitiGql
35
35
  end
36
36
 
37
37
  def customized_edge?
38
- @sideload.type == :many_to_many && @sideload.class.edge_resource
38
+ @sideload.type == :many_to_many && @sideload.edge_resource
39
39
  end
40
40
 
41
41
  def find_or_build_connection
@@ -59,21 +59,60 @@ module GraphitiGql
59
59
  end
60
60
 
61
61
  def build_edge_type_class(sideload_type)
62
- prior_edge_type_class = sideload_type.edge_type_class
63
- edge_type_class = Class.new(prior_edge_type_class)
64
- edge_resource = @sideload.class.edge_resource
65
- edge_resource.attributes.each_pair do |name, config|
66
- next if name == :id
67
- Schema::Fields::Attribute.new(edge_resource, name, config, @sideload).apply(edge_type_class)
62
+ klass = build_friendly_graphql_edge_type_class \
63
+ sideload_type.edge_type_class
64
+ name = edge_type_class_name(sideload_type)
65
+ klass.define_method(:graphql_name) { name }
66
+ klass.graphql_name(name)
67
+ edge_resource = @sideload.edge_resource
68
+ ResourceType.add_fields(klass, edge_resource, id: false)
69
+ ResourceType.add_relationships(edge_resource, klass)
70
+ klass
71
+ end
72
+
73
+ # Normally we reference 'object', but edges work differently
74
+ # This makes 'object' work everywhere
75
+ # Needed when evaluating fields/relationships for consistent interface
76
+ def build_friendly_graphql_edge_type_class(superklass)
77
+ klass = Class.new(superklass) do
78
+ alias :original_object :object
79
+ def object
80
+ return @_object if @_object # avoid conflict
81
+
82
+ node = original_object.node # the 'parent' record we joined with
83
+ edge_attrs = node.attributes.select { |k,v| k.to_s.starts_with?('_edge') }
84
+ edge_attrs.transform_keys! { |k| k.to_s.gsub('_edge_', '') }
85
+ edge_model = model.new(edge_attrs)
86
+ edge_model.instance_variable_set(:@__graphiti_resource, resource)
87
+ @_object = edge_model
88
+ @_object
89
+ end
90
+
91
+ def cursor
92
+ original_object.cursor
93
+ end
94
+
95
+ def node
96
+ original_object.node
97
+ end
68
98
  end
69
- registered_parent = Schema.registry.get(@sideload.parent_resource.class)
99
+
100
+ # used in #object
101
+ thru = @sideload.foreign_key.keys.first
102
+ reflection = @sideload.parent_resource.model.reflect_on_association(thru)
103
+ thru_model = reflection.klass
104
+ edge_resource = @sideload.edge_resource.new
105
+ klass.define_method(:model) { thru_model }
106
+ klass.define_method(:resource) { edge_resource }
107
+
108
+ klass
109
+ end
110
+
111
+ def edge_type_class_name(sideload_type)
112
+ registered_parent = Schema.registry.get \
113
+ @sideload.parent_resource.class
70
114
  parent_name = registered_parent[:type].graphql_name
71
- edge_type_class_name = "#{parent_name}To#{sideload_type.graphql_name}Edge"
72
- edge_type_class.define_method :graphql_name do
73
- edge_type_class_name
74
- end
75
- edge_type_class.graphql_name(edge_type_class_name)
76
- edge_type_class
115
+ "#{parent_name}To#{sideload_type.graphql_name}Edge"
77
116
  end
78
117
  end
79
118
  end
@@ -30,30 +30,9 @@ module GraphitiGql
30
30
  end
31
31
 
32
32
  def add_relationships
33
- each_relationship do |type, sideload_type, sideload|
34
- if [:has_many, :many_to_many, :has_one].include?(sideload.type)
35
- Fields::ToMany.new(sideload, sideload_type).apply(type)
36
- else
37
- Fields::ToOne.new(sideload, sideload_type).apply(type)
38
- end
39
- end
40
- end
41
-
42
- def each_relationship
43
33
  registry.resource_types.each do |registered|
44
- registered[:resource].sideloads.each do |name, sl|
45
- next unless sl.readable?
46
-
47
- registered_sl = if sl.type == :polymorphic_belongs_to
48
- PolymorphicBelongsToInterface
49
- .new(registered[:resource], sl)
50
- .build
51
- else
52
- registry.get(sl.resource.class)
53
- end
54
-
55
- yield registered[:type], registered_sl[:type], sl
56
- end
34
+ resource, type = registered[:resource], registered[:type]
35
+ ResourceType.add_relationships(resource, type)
57
36
  end
58
37
  end
59
38
  end
@@ -14,6 +14,36 @@ module GraphitiGql
14
14
  end
15
15
  end
16
16
 
17
+ def self.add_fields(type, resource, id: true)
18
+ resource.attributes.each_pair do |name, config|
19
+ next if name == :id && id == false
20
+ if config[:readable]
21
+ Fields::Attribute.new(resource, name, config).apply(type)
22
+ end
23
+ end
24
+ end
25
+
26
+ def self.add_relationships(resource, type)
27
+ resource.sideloads.each do |name, sideload|
28
+ next unless sideload.readable?
29
+
30
+ registered_sl = if sideload.type == :polymorphic_belongs_to
31
+ PolymorphicBelongsToInterface
32
+ .new(resource, sideload)
33
+ .build
34
+ else
35
+ Schema.registry.get(sideload.resource.class)
36
+ end
37
+ sideload_type = registered_sl[:type]
38
+
39
+ if [:has_many, :many_to_many, :has_one].include?(sideload.type)
40
+ Fields::ToMany.new(sideload, sideload_type).apply(type)
41
+ else
42
+ Fields::ToOne.new(sideload, sideload_type).apply(type)
43
+ end
44
+ end
45
+ end
46
+
17
47
  def initialize(resource, implements: nil)
18
48
  @resource = resource
19
49
  @implements = implements
@@ -86,14 +116,10 @@ module GraphitiGql
86
116
  def name
87
117
  registry.key_for(@resource)
88
118
  end
89
-
119
+
90
120
  def add_fields(type, resource)
91
- resource.attributes.each_pair do |name, config|
92
- if config[:readable]
93
- Fields::Attribute.new(@resource, name, config).apply(type)
94
- end
95
- end
96
- end
121
+ self.class.add_fields(type, resource)
122
+ end
97
123
 
98
124
  def build_connection_class
99
125
  klass = Class.new(GraphQL::Types::Relay::BaseConnection)
@@ -1,3 +1,3 @@
1
1
  module GraphitiGql
2
- VERSION = "0.2.20"
2
+ VERSION = "0.2.23"
3
3
  end
data/lib/graphiti_gql.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require "active_support/core_ext/object/json"
2
2
  require "graphql"
3
3
  require 'graphql/batch'
4
+ require 'active_model'
4
5
  require "graphiti_gql/graphiti_hax"
5
6
  require "graphiti_gql/version"
6
7
  require "graphiti_gql/errors"
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.20
4
+ version: 0.2.23
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lee Richmond
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-08-01 00:00:00.000000000 Z
11
+ date: 2022-08-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: graphql
@@ -52,6 +52,26 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: 1.3.9
55
+ - !ruby/object:Gem::Dependency
56
+ name: activemodel
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">"
60
+ - !ruby/object:Gem::Version
61
+ version: '6.0'
62
+ - - "<"
63
+ - !ruby/object:Gem::Version
64
+ version: '8.0'
65
+ type: :runtime
66
+ prerelease: false
67
+ version_requirements: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">"
70
+ - !ruby/object:Gem::Version
71
+ version: '6.0'
72
+ - - "<"
73
+ - !ruby/object:Gem::Version
74
+ version: '8.0'
55
75
  - !ruby/object:Gem::Dependency
56
76
  name: bundler
57
77
  requirement: !ruby/object:Gem::Requirement
@@ -94,21 +114,7 @@ dependencies:
94
114
  - - "~>"
95
115
  - !ruby/object:Gem::Version
96
116
  version: '3.0'
97
- - !ruby/object:Gem::Dependency
98
- name: activemodel
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - "~>"
102
- - !ruby/object:Gem::Version
103
- version: '7.0'
104
- type: :development
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - "~>"
109
- - !ruby/object:Gem::Version
110
- version: '7.0'
111
- description:
117
+ description:
112
118
  email:
113
119
  - richmolj@gmail.com
114
120
  executables: []
@@ -169,7 +175,7 @@ licenses:
169
175
  - MIT
170
176
  metadata:
171
177
  homepage_uri: https://www.graphiti.dev
172
- post_install_message:
178
+ post_install_message:
173
179
  rdoc_options: []
174
180
  require_paths:
175
181
  - lib
@@ -184,8 +190,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
184
190
  - !ruby/object:Gem::Version
185
191
  version: '0'
186
192
  requirements: []
187
- rubygems_version: 3.0.3.1
188
- signing_key:
193
+ rubygems_version: 3.3.7
194
+ signing_key:
189
195
  specification_version: 4
190
196
  summary: GraphQL support for Graphiti
191
197
  test_files: []