graphiti_gql 0.1.0
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 +7 -0
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/.travis.yml +7 -0
- data/Gemfile +9 -0
- data/Gemfile.lock +98 -0
- data/LICENSE.txt +21 -0
- data/README.md +3 -0
- data/Rakefile +6 -0
- data/bin/bundle +114 -0
- data/bin/byebug +27 -0
- data/bin/coderay +27 -0
- data/bin/console +14 -0
- data/bin/graphiti +27 -0
- data/bin/htmldiff +27 -0
- data/bin/ldiff +27 -0
- data/bin/pry +27 -0
- data/bin/rake +27 -0
- data/bin/rspec +27 -0
- data/bin/setup +8 -0
- data/config/routes.rb +6 -0
- data/graphiti_gql.gemspec +46 -0
- data/lib/graphiti_gql/engine.rb +29 -0
- data/lib/graphiti_gql/errors.rb +21 -0
- data/lib/graphiti_gql/graphiti_hax.rb +71 -0
- data/lib/graphiti_gql/loaders/belongs_to.rb +63 -0
- data/lib/graphiti_gql/loaders/has_many.rb +14 -0
- data/lib/graphiti_gql/loaders/many.rb +79 -0
- data/lib/graphiti_gql/loaders/many_to_many.rb +16 -0
- data/lib/graphiti_gql/loaders/polymorphic_has_many.rb +17 -0
- data/lib/graphiti_gql/response_shim.rb +13 -0
- data/lib/graphiti_gql/schema/connection.rb +57 -0
- data/lib/graphiti_gql/schema/fields/attribute.rb +46 -0
- data/lib/graphiti_gql/schema/fields/index.rb +33 -0
- data/lib/graphiti_gql/schema/fields/show.rb +33 -0
- data/lib/graphiti_gql/schema/fields/stats.rb +54 -0
- data/lib/graphiti_gql/schema/fields/to_many.rb +37 -0
- data/lib/graphiti_gql/schema/fields/to_one.rb +47 -0
- data/lib/graphiti_gql/schema/list_arguments.rb +127 -0
- data/lib/graphiti_gql/schema/polymorphic_belongs_to_interface.rb +35 -0
- data/lib/graphiti_gql/schema/query.rb +62 -0
- data/lib/graphiti_gql/schema/registry.rb +67 -0
- data/lib/graphiti_gql/schema/resource_type.rb +100 -0
- data/lib/graphiti_gql/schema/util.rb +74 -0
- data/lib/graphiti_gql/schema.rb +46 -0
- data/lib/graphiti_gql/version.rb +3 -0
- data/lib/graphiti_gql.rb +62 -0
- metadata +188 -0
@@ -0,0 +1,71 @@
|
|
1
|
+
# These should be in Graphiti itself, but can't do it quite yet b/c GQL coupling.
|
2
|
+
# Ideally we eventually rip out the parts of Graphiti we need and roll this into
|
3
|
+
# that effort.
|
4
|
+
module ResourceExtras
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
class << self
|
9
|
+
attr_accessor :graphql_name
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class_methods do
|
14
|
+
def attribute(*args)
|
15
|
+
super(*args).tap do
|
16
|
+
opts = args.extract_options!
|
17
|
+
att = config[:attributes][args[0]]
|
18
|
+
att[:deprecation_reason] = opts[:deprecation_reason]
|
19
|
+
att[:null] = opts.key?(:null) ? opts[:null] : args[0] != :id
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
Graphiti::Resource.send(:include, ResourceExtras)
|
26
|
+
|
27
|
+
module FilterExtras
|
28
|
+
def filter_param
|
29
|
+
default_filter = resource.default_filter if resource.respond_to?(:default_filter)
|
30
|
+
default_filter ||= {}
|
31
|
+
default_filter.merge(super)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
Graphiti::Scoping::Filter.send(:prepend, FilterExtras)
|
35
|
+
|
36
|
+
# ==================================================
|
37
|
+
# Below is all to support pagination argument 'last'
|
38
|
+
# ==================================================
|
39
|
+
module SortExtras
|
40
|
+
def sort_param
|
41
|
+
param = super
|
42
|
+
if query_hash[:reverse]
|
43
|
+
param = [{ id: :asc }] if param == []
|
44
|
+
param = param.map do |p|
|
45
|
+
{}.tap do |hash|
|
46
|
+
dir = p[p.keys.first]
|
47
|
+
dir = dir == :asc ? :desc : :asc
|
48
|
+
hash[p.keys.first] = dir
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
param
|
53
|
+
end
|
54
|
+
end
|
55
|
+
Graphiti::Scoping::Sort.send(:prepend, SortExtras)
|
56
|
+
module QueryExtras
|
57
|
+
def hash
|
58
|
+
hash = super
|
59
|
+
hash[:reverse] = true if @params[:reverse]
|
60
|
+
hash
|
61
|
+
end
|
62
|
+
end
|
63
|
+
Graphiti::Query.send(:prepend, QueryExtras)
|
64
|
+
module ScopeExtras
|
65
|
+
def resolve(*args)
|
66
|
+
results = super
|
67
|
+
results.reverse! if @query.hash[:reverse]
|
68
|
+
results
|
69
|
+
end
|
70
|
+
end
|
71
|
+
Graphiti::Scope.send(:prepend, ScopeExtras)
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module GraphitiGql
|
2
|
+
module Loaders
|
3
|
+
class FakeRecord < Struct.new(:id, :type)
|
4
|
+
end
|
5
|
+
|
6
|
+
class BelongsTo < GraphQL::Batch::Loader
|
7
|
+
def initialize(sideload, params)
|
8
|
+
@sideload = sideload
|
9
|
+
@params = params
|
10
|
+
end
|
11
|
+
|
12
|
+
def perform(ids)
|
13
|
+
# process nils
|
14
|
+
ids.each { |id| fulfill(id, nil) if id.nil? }
|
15
|
+
ids.compact!
|
16
|
+
return if ids.empty?
|
17
|
+
|
18
|
+
if @params[:simpleid]
|
19
|
+
if @sideload.type == :polymorphic_belongs_to
|
20
|
+
ids.each do |id|
|
21
|
+
child = @sideload.children.values.find { |c| c.group_name == id[:type].to_sym }
|
22
|
+
type = Schema::Registry.instance.get(child.resource.class, interface: false)[:type]
|
23
|
+
fulfill(id, FakeRecord.new(id[:id], type))
|
24
|
+
end
|
25
|
+
else
|
26
|
+
type = Schema::Registry.instance.get(@sideload.resource.class)[:type]
|
27
|
+
ids.each { |id| fulfill(id, FakeRecord.new(id, type)) }
|
28
|
+
end
|
29
|
+
return
|
30
|
+
end
|
31
|
+
|
32
|
+
if @sideload.type == :polymorphic_belongs_to
|
33
|
+
groups = ids.group_by { |hash| hash[:type] }
|
34
|
+
payload = {}
|
35
|
+
groups.each_pair do |key, val|
|
36
|
+
payload[key] = val.map { |v| v[:id] }
|
37
|
+
end
|
38
|
+
futures = []
|
39
|
+
payload.each_pair do |key, value|
|
40
|
+
params = { filter: {} }
|
41
|
+
klass = @sideload.children.values.find { |c| c.group_name == key.to_sym }
|
42
|
+
params = {
|
43
|
+
filter: { id: { eq: value.join(",") } }
|
44
|
+
}
|
45
|
+
futures << Concurrent::Future.execute do
|
46
|
+
{ type: key, data: klass.resource.class.all(params).data }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
values = futures.map(&:value)
|
50
|
+
ids.each do |id|
|
51
|
+
val = values.find { |v| v[:type] == id[:type] }
|
52
|
+
fulfill(id, val[:data][0])
|
53
|
+
end
|
54
|
+
else
|
55
|
+
params = {filter: {id: {eq: ids.join(",")}}}
|
56
|
+
records = @sideload.resource.class.all(params).data
|
57
|
+
map = records.index_by { |record| record.id }
|
58
|
+
ids.each { |id| fulfill(id, map[id]) }
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module GraphitiGql
|
2
|
+
module Loaders
|
3
|
+
class HasMany < Many
|
4
|
+
def assign(ids, proxy)
|
5
|
+
records = proxy.data
|
6
|
+
map = records.group_by { |record| record.send(@sideload.foreign_key) }
|
7
|
+
ids.each do |id|
|
8
|
+
data = [map[id] || [], proxy]
|
9
|
+
fulfill(id, data)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module GraphitiGql
|
2
|
+
module Loaders
|
3
|
+
class Many < GraphQL::Batch::Loader
|
4
|
+
def self.factory(sideload, params)
|
5
|
+
if sideload.polymorphic_as
|
6
|
+
PolymorphicHasMany.for(sideload, params)
|
7
|
+
elsif sideload.type == :many_to_many
|
8
|
+
ManyToMany.for(sideload, params)
|
9
|
+
else
|
10
|
+
HasMany.for(sideload, params)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(sideload, params)
|
15
|
+
@sideload = sideload
|
16
|
+
@params = params
|
17
|
+
end
|
18
|
+
|
19
|
+
def perform(ids)
|
20
|
+
raise ::Graphiti::Errors::UnsupportedPagination if paginating? && ids.length > 1
|
21
|
+
raise Errors::UnsupportedStats if requesting_stats? && ids.length > 1 && !can_group?
|
22
|
+
|
23
|
+
build_params(ids)
|
24
|
+
proxy = @sideload.resource.class.all(@params)
|
25
|
+
assign(ids, proxy)
|
26
|
+
end
|
27
|
+
|
28
|
+
def assign(ids, proxy)
|
29
|
+
raise "implement in subclass"
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def build_params(ids)
|
35
|
+
@params[:filter] ||= {}
|
36
|
+
|
37
|
+
if @sideload.polymorphic_as
|
38
|
+
type = ids[0][:"#{@sideload.polymorphic_as}_type"]
|
39
|
+
foreign_keys = ids.map { |id| id[@sideload.foreign_key] }
|
40
|
+
@params[:filter][:"#{@sideload.polymorphic_as}_type"] = type
|
41
|
+
@params[:filter][@sideload.foreign_key] = foreign_keys.join(",")
|
42
|
+
elsif @sideload.type == :many_to_many
|
43
|
+
fk = @sideload.foreign_key.values.first
|
44
|
+
@params[:filter].merge!(fk => { eq: ids.join(",") })
|
45
|
+
else
|
46
|
+
@params[:filter].merge!(@sideload.foreign_key => { eq: ids.join(",") })
|
47
|
+
end
|
48
|
+
|
49
|
+
if @params[:stats]
|
50
|
+
group_by = if @sideload.type ==:many_to_many
|
51
|
+
@sideload.foreign_key.values.first
|
52
|
+
else
|
53
|
+
@sideload.foreign_key
|
54
|
+
end
|
55
|
+
@params[:stats][:group_by] = group_by
|
56
|
+
end
|
57
|
+
|
58
|
+
unless @params.key?(:page) && @params[:page].key?(:size)
|
59
|
+
@params[:page] ||= {}
|
60
|
+
@params[:page][:size] = 999
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def paginating?
|
65
|
+
pagination_key_present = @params.key?(:page) &&
|
66
|
+
[:size, :last, :before, :after].any? { |arg| @params[:page].key?(arg) }
|
67
|
+
pagination_key_present && @params[:page][:size] != 0 # stats
|
68
|
+
end
|
69
|
+
|
70
|
+
def requesting_stats?
|
71
|
+
@params.key?(:stats)
|
72
|
+
end
|
73
|
+
|
74
|
+
def can_group?
|
75
|
+
@sideload.resource.adapter.can_group?
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module GraphitiGql
|
2
|
+
module Loaders
|
3
|
+
class ManyToMany < Many
|
4
|
+
def assign(ids, proxy)
|
5
|
+
records = proxy.data
|
6
|
+
thru = @sideload.foreign_key.keys.first
|
7
|
+
fk = @sideload.foreign_key[thru]
|
8
|
+
ids.each do |id|
|
9
|
+
match = ->(thru) { thru.send(fk) == id }
|
10
|
+
corresponding = records.select { |record| record.send(thru).any?(&match) }
|
11
|
+
fulfill(id, [corresponding, proxy])
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module GraphitiGql
|
2
|
+
module Loaders
|
3
|
+
class PolymorphicHasMany < Many
|
4
|
+
def assign(ids, proxy)
|
5
|
+
records = proxy.data
|
6
|
+
ids.each do |id|
|
7
|
+
corresponding = records.select do |record|
|
8
|
+
record.send("#{@sideload.polymorphic_as}_type") == id[:"#{@sideload.polymorphic_as}_type"] &&
|
9
|
+
record.send(@sideload.foreign_key) == id[@sideload.foreign_key]
|
10
|
+
end
|
11
|
+
data = [corresponding || [], proxy]
|
12
|
+
fulfill(id, data)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module GraphitiGql
|
2
|
+
class Schema
|
3
|
+
class Connection < ::GraphQL::Pagination::Connection
|
4
|
+
def nodes
|
5
|
+
return @items if @run_once
|
6
|
+
@proxy = @items.proxy
|
7
|
+
@items = @items.data
|
8
|
+
@run_once = true
|
9
|
+
@items
|
10
|
+
end
|
11
|
+
|
12
|
+
def proxy
|
13
|
+
nodes
|
14
|
+
@proxy
|
15
|
+
end
|
16
|
+
|
17
|
+
def has_previous_page
|
18
|
+
proxy.pagination.has_previous_page?
|
19
|
+
end
|
20
|
+
|
21
|
+
def has_next_page
|
22
|
+
nodes
|
23
|
+
return false if @items.length.zero?
|
24
|
+
cursor = JSON.parse(Base64.decode64(cursor_for(@items.last)))
|
25
|
+
cursor["offset"] < @proxy.pagination.send(:item_count)
|
26
|
+
end
|
27
|
+
|
28
|
+
def cursor_for(item)
|
29
|
+
nodes
|
30
|
+
starting_offset = 0
|
31
|
+
page_param = proxy.query.pagination
|
32
|
+
if (page_number = page_param[:number])
|
33
|
+
page_size = page_param[:size] || proxy.resource.default_page_size
|
34
|
+
starting_offset = (page_number - 1) * page_size
|
35
|
+
end
|
36
|
+
|
37
|
+
if (cursor = page_param[:after])
|
38
|
+
starting_offset = cursor[:offset]
|
39
|
+
end
|
40
|
+
|
41
|
+
current_offset = @items.index(item)
|
42
|
+
offset = starting_offset + current_offset + 1 # (+ 1 b/c o-base index)
|
43
|
+
Base64.encode64({offset: offset}.to_json).chomp
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class ToManyConnection < Connection
|
48
|
+
def nodes
|
49
|
+
return @items if @run_once
|
50
|
+
@proxy = @items[1]
|
51
|
+
@items = @items[0]
|
52
|
+
@run_once = true
|
53
|
+
@items
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module GraphitiGql
|
2
|
+
class Schema
|
3
|
+
module Fields
|
4
|
+
class Attribute
|
5
|
+
def initialize(name, config)
|
6
|
+
@name = name
|
7
|
+
@config = config
|
8
|
+
end
|
9
|
+
|
10
|
+
def apply(type)
|
11
|
+
is_nullable = !!@config[:null]
|
12
|
+
_config = @config
|
13
|
+
_name = @name
|
14
|
+
opts = @config.slice(:null, :deprecation_reason)
|
15
|
+
type.field(@name, field_type, **opts)
|
16
|
+
type.define_method @name do
|
17
|
+
if (readable = _config[:readable]).is_a?(Symbol)
|
18
|
+
resource = object.instance_variable_get(:@__graphiti_resource)
|
19
|
+
unless resource.send(readable)
|
20
|
+
path = Graphiti.context[:object][:current_path].join(".")
|
21
|
+
raise Errors::UnauthorizedField.new(path)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
value = if _config[:proc]
|
25
|
+
instance_eval(&_config[:proc])
|
26
|
+
else
|
27
|
+
object.send(_name)
|
28
|
+
end
|
29
|
+
return if value.nil?
|
30
|
+
Graphiti::Types[_config[:type]][:read].call(value)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def field_type
|
37
|
+
canonical_graphiti_type = Graphiti::Types.name_for(@config[:type])
|
38
|
+
field_type = GQL_TYPE_MAP[canonical_graphiti_type.to_sym]
|
39
|
+
field_type = String if @name == :id
|
40
|
+
field_type = [field_type] if @config[:type].to_s.starts_with?("array_of")
|
41
|
+
field_type
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module GraphitiGql
|
2
|
+
class Schema
|
3
|
+
module Fields
|
4
|
+
class Index
|
5
|
+
def initialize(registered)
|
6
|
+
@registered = registered
|
7
|
+
end
|
8
|
+
|
9
|
+
def apply(query)
|
10
|
+
resource = @registered[:resource]
|
11
|
+
field = query.field resource.graphql_entrypoint,
|
12
|
+
@registered[:type].connection_type,
|
13
|
+
null: false,
|
14
|
+
connection: false,
|
15
|
+
extensions: [RelayConnectionExtension],
|
16
|
+
extras: [:lookahead]
|
17
|
+
ListArguments.new(resource).apply(field)
|
18
|
+
query.define_method name do |**arguments|
|
19
|
+
params = Util.params_from_args(arguments)
|
20
|
+
proxy = resource.all(params)
|
21
|
+
ResponseShim.new(proxy.data, proxy)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def name
|
28
|
+
@registered[:resource].graphql_entrypoint
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module GraphitiGql
|
2
|
+
class Schema
|
3
|
+
module Fields
|
4
|
+
class Show
|
5
|
+
def initialize(registered)
|
6
|
+
@registered = registered
|
7
|
+
end
|
8
|
+
|
9
|
+
def apply(query)
|
10
|
+
field = query.field name,
|
11
|
+
@registered[:type],
|
12
|
+
null: true,
|
13
|
+
extras: [:lookahead]
|
14
|
+
field.argument(:id, String, required: true)
|
15
|
+
_registered = @registered
|
16
|
+
query.define_method name do |**arguments|
|
17
|
+
params = Util.params_from_args(arguments)
|
18
|
+
_registered[:resource].all(params).data[0]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def name
|
25
|
+
@registered[:resource]
|
26
|
+
.graphql_entrypoint.to_s
|
27
|
+
.underscore
|
28
|
+
.singularize.to_sym
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module GraphitiGql
|
2
|
+
class Schema
|
3
|
+
module Fields
|
4
|
+
class Stats
|
5
|
+
def initialize(resource)
|
6
|
+
@resource = resource
|
7
|
+
end
|
8
|
+
|
9
|
+
def apply(type)
|
10
|
+
type.field :stats, build_stat_class, null: false
|
11
|
+
type.define_method :stats do
|
12
|
+
# 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]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
stats
|
22
|
+
end
|
23
|
+
type
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def build_stat_class
|
29
|
+
name = Registry.instance.key_for(@resource)
|
30
|
+
stat_graphql_name = "#{name}Stats"
|
31
|
+
return Registry.instance[stat_graphql_name][:type] if Registry.instance[stat_graphql_name]
|
32
|
+
klass = Class.new(GraphQL::Schema::Object)
|
33
|
+
klass.graphql_name(stat_graphql_name)
|
34
|
+
@resource.stats.each_pair do |name, config|
|
35
|
+
calc_class = build_calc_class(stat_graphql_name, name, config.calculations.keys)
|
36
|
+
klass.field name, calc_class, null: false
|
37
|
+
end
|
38
|
+
Registry.instance[stat_graphql_name] = { type: klass }
|
39
|
+
klass
|
40
|
+
end
|
41
|
+
|
42
|
+
def build_calc_class(stat_graphql_name, stat_name, calculations)
|
43
|
+
name = "#{stat_graphql_name}#{stat_name}Calculations"
|
44
|
+
klass = Class.new(GraphQL::Schema::Object)
|
45
|
+
klass.graphql_name(name)
|
46
|
+
calculations.each do |calc|
|
47
|
+
klass.field calc, Float, null: false
|
48
|
+
end
|
49
|
+
klass
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module GraphitiGql
|
2
|
+
class Schema
|
3
|
+
module Fields
|
4
|
+
class ToMany
|
5
|
+
def initialize(sideload, sideload_type)
|
6
|
+
@sideload = sideload
|
7
|
+
@sideload_type = sideload_type
|
8
|
+
end
|
9
|
+
|
10
|
+
def apply(type)
|
11
|
+
field = type.field @sideload.name,
|
12
|
+
@sideload_type.connection_type,
|
13
|
+
null: false,
|
14
|
+
connection: false,
|
15
|
+
extensions: [RelayConnectionExtension],
|
16
|
+
extras: [:lookahead]
|
17
|
+
ListArguments.new(@sideload.resource.class, @sideload).apply(field)
|
18
|
+
_sideload = @sideload
|
19
|
+
type.define_method(@sideload.name) do |**arguments|
|
20
|
+
Util.is_readable_sideload!(_sideload)
|
21
|
+
params = Util.params_from_args(arguments)
|
22
|
+
pk = object.send(_sideload.primary_key)
|
23
|
+
id = if _sideload.polymorphic_as
|
24
|
+
hash = {}
|
25
|
+
hash[_sideload.foreign_key] = pk
|
26
|
+
hash[:"#{_sideload.polymorphic_as}_type"] = object.class.name
|
27
|
+
id = hash
|
28
|
+
else
|
29
|
+
id = pk
|
30
|
+
end
|
31
|
+
Loaders::Many.factory(_sideload, params).load(id)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module GraphitiGql
|
2
|
+
class Schema
|
3
|
+
module Fields
|
4
|
+
class ToOne
|
5
|
+
def initialize(sideload, sideload_type)
|
6
|
+
@sideload = sideload
|
7
|
+
@sideload_type = sideload_type
|
8
|
+
end
|
9
|
+
|
10
|
+
def apply(type)
|
11
|
+
field = type.field @sideload.name,
|
12
|
+
@sideload_type,
|
13
|
+
null: true,
|
14
|
+
extras: [:lookahead]
|
15
|
+
_sideload = @sideload
|
16
|
+
type.define_method(@sideload.name) do |**arguments|
|
17
|
+
Util.is_readable_sideload!(_sideload)
|
18
|
+
|
19
|
+
if _sideload.type == :has_one
|
20
|
+
id = object.send(_sideload.primary_key)
|
21
|
+
params = { filter: { _sideload.foreign_key => { eq: id } } }
|
22
|
+
return _sideload.resource.class.all(params).data[0]
|
23
|
+
end
|
24
|
+
|
25
|
+
lookahead = arguments[:lookahead]
|
26
|
+
id = object.send(_sideload.foreign_key)
|
27
|
+
if id.nil?
|
28
|
+
Loaders::BelongsTo.for(_sideload, {}).load(nil)
|
29
|
+
else
|
30
|
+
params = Util.params_from_args(arguments)
|
31
|
+
|
32
|
+
if _sideload.type == :polymorphic_belongs_to
|
33
|
+
id = { id: id, type: object.send(_sideload.grouper.field_name) }
|
34
|
+
end
|
35
|
+
|
36
|
+
selections = lookahead.selections.map(&:name).sort
|
37
|
+
if selections == [:id] || selections == [:__typename, :id]
|
38
|
+
params[:simpleid] = true
|
39
|
+
end
|
40
|
+
Loaders::BelongsTo.for(_sideload, params).load(id)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|