graphiti_gql 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|