Class: GraphQL::Dataloader::Source

Inherits:
Object
  • Object
show all
Defined in:
lib/graphql/dataloader/source.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#dataloaderObject (readonly)

Returns the value of attribute dataloader.



14
15
16
# File 'lib/graphql/dataloader/source.rb', line 14

def dataloader
  @dataloader
end

Class Method Details

.batch_key_for(*batch_args, **batch_kwargs) ⇒ Object

These arguments are given to dataloader.with(source_class, ...). The object returned from this method is used to de-duplicate batch loads under the hood by using it as a Hash key.

By default, the arguments are all put in an Array. To customize how this source’s batches are merged, override this method to return something else.

For example, if you pass ActiveRecord::Relations to .with(...), you could override this method to call .to_sql on them, thus merging .load(...) calls when they apply to equivalent relations.

Parameters:

  • batch_args (Array<Object>)
  • batch_kwargs (Hash)

Returns:

  • (Object)


106
107
108
# File 'lib/graphql/dataloader/source.rb', line 106

def self.batch_key_for(*batch_args, **batch_kwargs)
  [*batch_args, **batch_kwargs]
end

Instance Method Details

#fetch(keys) ⇒ Array<Object>

Subclasses must implement this method to return a value for each of keys

Parameters:

Returns:

  • (Array<Object>)

    A loaded value for each of keys. The array must match one-for-one to the list of keys.



58
59
60
61
# File 'lib/graphql/dataloader/source.rb', line 58

def fetch(keys)
  # somehow retrieve these from the backend
  raise "Implement `#{self.class}#fetch(#{keys.inspect}) to return a record for each of the keys"
end

#load(key) ⇒ Object

Returns The result from #fetch for key. If key hasn’t been loaded yet, the Fiber will yield until it’s loaded.

Parameters:

  • key (Object)

    A loading key which will be passed to #fetch if it isn’t already in the internal cache.

Returns:

  • (Object)

    The result from #fetch for key. If key hasn’t been loaded yet, the Fiber will yield until it’s loaded.



33
34
35
36
37
38
39
40
41
# File 'lib/graphql/dataloader/source.rb', line 33

def load(key)
  if @results.key?(key)
    result_for(key)
  else
    @pending_keys << key
    sync
    result_for(key)
  end
end

#load_all(keys) ⇒ Object

Returns The result from #fetch for keys. If keys haven’t been loaded yet, the Fiber will yield until they’re loaded.

Parameters:

  • keys (Array<Object>)

    Loading keys which will be passed to #fetch (or read from the internal cache).

Returns:

  • (Object)

    The result from #fetch for keys. If keys haven’t been loaded yet, the Fiber will yield until they’re loaded.



45
46
47
48
49
50
51
52
53
# File 'lib/graphql/dataloader/source.rb', line 45

def load_all(keys)
  if keys.any? { |k| !@results.key?(k) }
    pending_keys = keys.select { |k| !@results.key?(k) }
    @pending_keys.concat(pending_keys)
    sync
  end

  keys.map { |k| result_for(k) }
end

#pending?Boolean

Returns True if this source has any pending requests for data.

Returns:

  • (Boolean)

    True if this source has any pending requests for data.



71
72
73
# File 'lib/graphql/dataloader/source.rb', line 71

def pending?
  @pending_keys.any?
end

#request(key) ⇒ Dataloader::Request

Returns a pending request for a value from key. Call .load on that object to wait for the result.

Returns:

  • (Dataloader::Request)

    a pending request for a value from key. Call .load on that object to wait for the result.



17
18
19
20
21
22
# File 'lib/graphql/dataloader/source.rb', line 17

def request(key)
  if !@results.key?(key)
    @pending_keys << key
  end
  Dataloader::Request.new(self, key)
end

#request_all(keys) ⇒ Dataloader::Request

Returns a pending request for a values from keys. Call .load on that object to wait for the results.

Returns:

  • (Dataloader::Request)

    a pending request for a values from keys. Call .load on that object to wait for the results.



25
26
27
28
29
# File 'lib/graphql/dataloader/source.rb', line 25

def request_all(keys)
  pending_keys = keys.select { |k| !@results.key?(k) }
  @pending_keys.concat(pending_keys)
  Dataloader::RequestAll.new(self, keys)
end

#run_pending_keysvoid

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

This method returns an undefined value.

Called by GraphQL::Dataloader to resolve and pending requests to this source.



78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/graphql/dataloader/source.rb', line 78

def run_pending_keys
  return if @pending_keys.empty?
  fetch_keys = @pending_keys.uniq
  @pending_keys = []
  results = fetch(fetch_keys)
  fetch_keys.each_with_index do |key, idx|
    @results[key] = results[idx]
  end
rescue StandardError => error
  fetch_keys.each { |key| @results[key] = error }
ensure
  nil
end

#setup(dataloader) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Called by GraphQL::Dataloader to prepare the GraphQL::Dataloader::Source’s internal state



8
9
10
11
12
# File 'lib/graphql/dataloader/source.rb', line 8

def setup(dataloader)
  @pending_keys = []
  @results = {}
  @dataloader = dataloader
end

#syncvoid

This method returns an undefined value.

Wait for a batch, if there’s anything to batch. Then run the batch and update the cache.



66
67
68
# File 'lib/graphql/dataloader/source.rb', line 66

def sync
  @dataloader.yield
end