graphiti_gql 0.2.23 → 0.2.26
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 +3 -3
- data/lib/graphiti_gql/graphiti_hax.rb +136 -0
- data/lib/graphiti_gql/schema/fields/attribute.rb +5 -1
- data/lib/graphiti_gql/schema/fields/to_many.rb +1 -0
- data/lib/graphiti_gql/schema/query.rb +8 -0
- data/lib/graphiti_gql/schema/registry.rb +2 -1
- data/lib/graphiti_gql/schema/resource_type.rb +36 -1
- data/lib/graphiti_gql/schema.rb +37 -2
- data/lib/graphiti_gql/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 00d26d5be2b1e9f1f277e0d0922faec91599f72a28fabe77ff16fb1f2ae6870f
|
4
|
+
data.tar.gz: a868703b6bf2a2fbf88464396f0fe17ba836ffc183cee22e2aad06b5bd6a1223
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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.
|
24
|
+
dry-container (0.10.1)
|
25
25
|
concurrent-ruby (~> 1.0)
|
26
|
-
dry-core (0.8.
|
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.
|
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)
|
@@ -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)
|
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?
|
data/lib/graphiti_gql/schema.rb
CHANGED
@@ -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::
|
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
|
data/lib/graphiti_gql/version.rb
CHANGED
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.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-
|
11
|
+
date: 2022-08-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: graphql
|