graphiti_gql 0.2.23 → 0.2.26

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: c5dfc016180ec5fd536f236be63b24cad42471a74d44ab234dee1966f2de942e
4
- data.tar.gz: f97bbe243fa4a205004abdbd522942005b09e87fa37ba1db465000b383e355d0
3
+ metadata.gz: 00d26d5be2b1e9f1f277e0d0922faec91599f72a28fabe77ff16fb1f2ae6870f
4
+ data.tar.gz: a868703b6bf2a2fbf88464396f0fe17ba836ffc183cee22e2aad06b5bd6a1223
5
5
  SHA512:
6
- metadata.gz: '08c76642c2b6be4401a6efcce4c9070c52eee1661c333bcefc30a328826a0558aa6ed013028cb4d173bb2b47565aeeda18c2648a946d6ebe1dbcde2147325ced'
7
- data.tar.gz: d16a38a32815b6df020817bb5797ac26ce6507a443375955aad3c2c1fe8fe29192dbf0f01a854d6d565946daae1fe9a713c67df050bbc230c320c282a35e339f
6
+ metadata.gz: 02f91817b443a31d0eaa280316ddd1ab18691936e401c431a38354370f8a6a1b435076fa022df6d37041f35e08d06fb99fc8104aa957cca4e3b9507bba828117
7
+ data.tar.gz: 94ca96b977800303c54ecf61fabfeeca65c4b839fc1ae501e6192fdbb30af86181a1aada59d64a47339c28ff3ca4e5469d071a27db9280a59e8c0b339b0f70f6
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- graphiti_gql (0.2.23)
4
+ graphiti_gql (0.2.26)
5
5
  activemodel (> 6.0, < 8.0)
6
6
  graphiti (~> 1.3.9)
7
7
  graphql (~> 2.0)
@@ -21,9 +21,9 @@ GEM
21
21
  coderay (1.1.3)
22
22
  concurrent-ruby (1.1.10)
23
23
  diff-lcs (1.5.0)
24
- dry-container (0.10.0)
24
+ dry-container (0.10.1)
25
25
  concurrent-ruby (~> 1.0)
26
- dry-core (0.8.0)
26
+ dry-core (0.8.1)
27
27
  concurrent-ruby (~> 1.0)
28
28
  dry-inflector (0.3.0)
29
29
  dry-logic (1.2.0)
@@ -25,6 +25,10 @@ module GraphitiGql
25
25
  end
26
26
  end
27
27
 
28
+ def value_object?
29
+ self.class.value_object?
30
+ end
31
+
28
32
  def filterings
29
33
  @filterings ||= begin
30
34
  if @params.key?(:filter)
@@ -67,6 +71,11 @@ module GraphitiGql
67
71
  end
68
72
 
69
73
  class_methods do
74
+ def config
75
+ return @config if @config
76
+ super
77
+ @config = @config.merge(value_objects: {}, is_value_object: false)
78
+ end
70
79
 
71
80
  def attribute(*args)
72
81
  super(*args).tap do
@@ -79,7 +88,14 @@ module GraphitiGql
79
88
  end
80
89
 
81
90
  def filter(name, *args, &blk)
91
+ is_bool = (filters[name] && filters[name][:type] == :boolean) ||
92
+ args[0] == :boolean
93
+ opts = args.length == 1 ? args[0] : args[1]
94
+ boolean_array = is_bool && opts[:single] == false
82
95
  super
96
+ # default behavior is to force single: true
97
+ filters[name][:single] = false if boolean_array
98
+
83
99
  opts = args.extract_options!
84
100
  if opts[:if]
85
101
  attributes[name][:filterable] = opts[:if]
@@ -93,6 +109,40 @@ module GraphitiGql
93
109
  super
94
110
  end
95
111
  end
112
+
113
+ def value_object?
114
+ !!config[:is_value_object]
115
+ end
116
+
117
+ def value_object!
118
+ config[:is_value_object] = true
119
+ self.adapter = ::Graphiti::Adapters::Null
120
+ config[:filters] = {}
121
+ config[:stats] = {}
122
+ config[:sorts] = {}
123
+ config[:attributes].delete(:id)
124
+ define_method :base_scope do
125
+ {}
126
+ end
127
+ define_method :resolve do |parent|
128
+ [parent]
129
+ end
130
+ end
131
+
132
+ def value_object(name, opts = {})
133
+ opts[:array] ||= false
134
+ opts[:null] = true if opts[:null] != false
135
+ config[:value_objects][name] = Graphiti::ValueObjectAssociation.new(
136
+ name,
137
+ parent_resource_class: self,
138
+ resource_class: opts[:resource],
139
+ _alias: opts[:alias],
140
+ is_array: opts[:array],
141
+ null: opts[:null],
142
+ readable: opts[:readable],
143
+ deprecation_reason: opts[:deprecation_reason]
144
+ )
145
+ end
96
146
  end
97
147
  end
98
148
  Graphiti::Resource.send(:prepend, ResourceExtras)
@@ -264,6 +314,20 @@ module GraphitiGql
264
314
  description: 'Datetime with milliseconds'
265
315
  }
266
316
 
317
+ [:string, :integer, :float, :datetime, :precise_datetime].each do |kind|
318
+ duped_hash = Graphiti::Util::Hash.deep_dup(Graphiti::Types[:hash])
319
+ type = Graphiti::Types[:"#{kind}_range"] = duped_hash
320
+ type[:canonical_name] = :"#{kind}_range"
321
+ Graphiti::Types[:"array_of_#{kind}_ranges"] = {
322
+ canonical_name: :"#{kind}_range",
323
+ params: Dry::Types["strict.array"].of(type[:params]),
324
+ read: Dry::Types["strict.array"].of(type[:read]),
325
+ write: Dry::Types["strict.array"].of(type[:write]),
326
+ kind: "array",
327
+ description: "Base Type."
328
+ }
329
+ end
330
+
267
331
  module ActiveRecordAdapterExtras
268
332
  extend ActiveSupport::Concern
269
333
 
@@ -363,8 +427,18 @@ module GraphitiGql
363
427
 
364
428
  Graphiti::Query.send(:prepend, QueryExtras)
365
429
  module ScopeExtras
430
+ def initialize(object, resource, query, opts = {})
431
+ if resource.value_object?
432
+ object = query.params[:parent]
433
+ super(object, resource, query, opts)
434
+ else
435
+ super
436
+ end
437
+ end
438
+
366
439
  def resolve(*args)
367
440
  results = super
441
+ raise Graphiti::Errors::InvalidResolve unless results.is_a?(Array)
368
442
  results.reverse! if @query.hash[:reverse]
369
443
  results
370
444
  end
@@ -383,4 +457,66 @@ module GraphitiGql
383
457
  ::Graphiti::Adapters::ActiveRecord::ManyToManySideload
384
458
  .send(:prepend, ActiveRecordManyToManyExtras)
385
459
  end
460
+ end
461
+
462
+ class Graphiti::Errors::InvalidResolve < Graphiti::Errors::Base
463
+ def message
464
+ "Resource#resolve must always return an array"
465
+ end
466
+ end
467
+
468
+ class Graphiti::Errors::InvalidValueObject < Graphiti::Errors::Base
469
+ def initialize(resource, name, value)
470
+ @resource = resource
471
+ @name = name
472
+ @value = value
473
+ end
474
+
475
+ def message
476
+ "#{@resource} - value object '#{@name}' configured with array: true but returned non-array: #{@value.inspect}"
477
+ end
478
+ end
479
+
480
+ class Graphiti::ValueObjectAssociation
481
+ attr_reader :name,
482
+ :parent_resource_class,
483
+ :alias,
484
+ :readable,
485
+ :null,
486
+ :deprecation_reason
487
+
488
+ def initialize(
489
+ name,
490
+ parent_resource_class:,
491
+ resource_class:,
492
+ is_array: false,
493
+ readable: nil,
494
+ null: true,
495
+ _alias: nil,
496
+ deprecation_reason: nil
497
+ )
498
+ @name = name
499
+ @parent_resource_class = parent_resource_class
500
+ @resource_class = resource_class
501
+ @readable = readable
502
+ @array = is_array
503
+ @alias = _alias
504
+ @null = null
505
+ @deprecation_reason = deprecation_reason
506
+ end
507
+
508
+ def array?
509
+ !!@array
510
+ end
511
+
512
+ def resource_class
513
+ @resource_class ||= Graphiti::Util::Class
514
+ .infer_resource_class(@parent_resource_class, name)
515
+ end
516
+
517
+ def build_resource(parent)
518
+ instance = resource_class.new
519
+ instance.parent = parent
520
+ instance
521
+ end
386
522
  end
@@ -30,7 +30,11 @@ module GraphitiGql
30
30
  value = if _config[:proc]
31
31
  instance_eval(&_config[:proc])
32
32
  else
33
- object.send(_alias || _name)
33
+ if object.is_a?(Hash)
34
+ object[_name] || object[_name.to_s]
35
+ else
36
+ object.send(_alias || _name)
37
+ end
34
38
  end
35
39
  return if value.nil?
36
40
  Graphiti::Types[_config[:type]][:read].call(value)
@@ -67,6 +67,7 @@ module GraphitiGql
67
67
  edge_resource = @sideload.edge_resource
68
68
  ResourceType.add_fields(klass, edge_resource, id: false)
69
69
  ResourceType.add_relationships(edge_resource, klass)
70
+ ResourceType.add_value_objects(edge_resource, klass)
70
71
  klass
71
72
  end
72
73
 
@@ -10,6 +10,7 @@ module GraphitiGql
10
10
  def build
11
11
  @resources.each { |resource| ResourceType.new(resource).build }
12
12
  define_entrypoints
13
+ add_value_objects
13
14
  add_relationships
14
15
  @query_class
15
16
  end
@@ -35,6 +36,13 @@ module GraphitiGql
35
36
  ResourceType.add_relationships(resource, type)
36
37
  end
37
38
  end
39
+
40
+ def add_value_objects
41
+ registry.resource_types.each do |registered|
42
+ resource, type = registered[:resource], registered[:type]
43
+ ResourceType.add_value_objects(resource, type)
44
+ end
45
+ end
38
46
  end
39
47
  end
40
48
  end
@@ -52,7 +52,8 @@ module GraphitiGql
52
52
  # When polymorphic parent, returns the Interface not the Class
53
53
  def resource_types
54
54
  values
55
- .select { |v| v.key?(:resource) && !v[:interface] }
55
+ .select { |v| v.key?(:resource) }
56
+ .reject { |v| v[:interface] || v[:resource].value_object? }
56
57
  .map { |registered| get(registered[:resource]) }
57
58
  end
58
59
 
@@ -14,7 +14,7 @@ module GraphitiGql
14
14
  end
15
15
  end
16
16
 
17
- def self.add_fields(type, resource, id: true)
17
+ def self.add_fields(type, resource, id: true) # id: false for edges
18
18
  resource.attributes.each_pair do |name, config|
19
19
  next if name == :id && id == false
20
20
  if config[:readable]
@@ -23,6 +23,41 @@ module GraphitiGql
23
23
  end
24
24
  end
25
25
 
26
+ def self.add_value_objects(resource, type)
27
+ resource.config[:value_objects].each_pair do |name, vo_association|
28
+ vo_resource_class = vo_association.resource_class
29
+ value_object_type = Schema.registry.get(vo_resource_class)[:type]
30
+ if vo_association.array?
31
+ value_object_type = [value_object_type]
32
+ end
33
+
34
+ _array = vo_association.array?
35
+ opts = { null: vo_association.null }
36
+ opts[:deprecation_reason] = vo_association.deprecation_reason if vo_association.deprecation_reason
37
+ type.field name, value_object_type, **opts
38
+ type.define_method name do
39
+ if (method_name = vo_association.readable)
40
+ unless vo_association.parent_resource_class.new.send(method_name)
41
+ raise ::Graphiti::Errors::UnreadableAttribute
42
+ .new(vo_association.parent_resource_class, name)
43
+ end
44
+ end
45
+
46
+ result = vo_resource_class.all({ parent: object }).to_a
47
+ default_behavior = result == [object]
48
+ result = result.first if !_array
49
+ if default_behavior
50
+ method_name = vo_association.alias.presence || name
51
+ result = object.send(method_name)
52
+ if _array && !result.is_a?(Array)
53
+ raise Graphiti::Errors::InvalidValueObject.new(resource, name, result)
54
+ end
55
+ end
56
+ result
57
+ end
58
+ end
59
+ end
60
+
26
61
  def self.add_relationships(resource, type)
27
62
  resource.sideloads.each do |name, sideload|
28
63
  next unless sideload.readable?
@@ -4,6 +4,31 @@ module GraphitiGql
4
4
  self.time_precision = 6
5
5
  end
6
6
 
7
+ class DatetimeRange < GraphQL::Schema::Object
8
+ field :from, GraphQL::Types::ISO8601DateTime
9
+ field :to, GraphQL::Types::ISO8601DateTime
10
+ end
11
+
12
+ class PreciseDatetimeRange < GraphQL::Schema::Object
13
+ field :from, PreciseDatetime
14
+ field :to, PreciseDatetime
15
+ end
16
+
17
+ class StringRange < GraphQL::Schema::Object
18
+ field :from, String
19
+ field :to, String
20
+ end
21
+
22
+ class IntegerRange < GraphQL::Schema::Object
23
+ field :from, Integer
24
+ field :to, Integer
25
+ end
26
+
27
+ class FloatRange < GraphQL::Schema::Object
28
+ field :from, Float
29
+ field :to, Float
30
+ end
31
+
7
32
  GQL_TYPE_MAP = {
8
33
  integer_id: String,
9
34
  string: String,
@@ -11,18 +36,28 @@ module GraphitiGql
11
36
  integer: Integer,
12
37
  big_integer: GraphQL::Types::BigInt,
13
38
  float: Float,
14
- boolean: GraphQL::Schema::Member::GraphQLTypeNames::Boolean,
39
+ boolean: GraphQL::Types::Boolean,
15
40
  date: GraphQL::Types::ISO8601Date,
16
41
  datetime: GraphQL::Types::ISO8601DateTime,
17
42
  precise_datetime: PreciseDatetime,
18
43
  hash: GraphQL::Types::JSON,
44
+ string_range: StringRange,
45
+ integer_range: IntegerRange,
46
+ float_range: FloatRange,
47
+ datetime_range: DatetimeRange,
48
+ precise_datetime_range: PreciseDatetimeRange,
19
49
  array: [GraphQL::Types::JSON],
20
50
  array_of_strings: [String],
21
51
  array_of_integers: [Integer],
22
52
  array_of_floats: [Float],
23
53
  array_of_dates: [GraphQL::Types::ISO8601Date],
24
54
  array_of_datetimes: [GraphQL::Types::ISO8601DateTime],
25
- array_of_precise_datetimes: [PreciseDatetime]
55
+ array_of_precise_datetimes: [PreciseDatetime],
56
+ array_of_string_ranges: [StringRange],
57
+ array_of_integer_ranges: [IntegerRange],
58
+ array_of_float_ranges: [FloatRange],
59
+ array_of_datetime_ranges: [DatetimeRange],
60
+ array_of_precise_datetime_ranges: [PreciseDatetimeRange]
26
61
  }
27
62
 
28
63
  class RelayConnectionExtension < GraphQL::Schema::Field::ConnectionExtension
@@ -1,3 +1,3 @@
1
1
  module GraphitiGql
2
- VERSION = "0.2.23"
2
+ VERSION = "0.2.26"
3
3
  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.23
4
+ version: 0.2.26
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-10 00:00:00.000000000 Z
11
+ date: 2022-08-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: graphql