Class: Rails::GraphQL::Subscription::Store::Memory

Inherits:
Base
  • Object
show all
Defined in:
lib/rails/graphql/subscription/store/memory.rb

Overview

GraphQL Memory Subscription Store

This store will save all the subscriptions in a very similar way that the TypeMap works, using nested concurrent maps that points out to them. Everything is based on the sid of the subscription

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods inherited from Base

new

Constructor Details

#initializeMemory

Returns a new instance of Memory.



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/rails/graphql/subscription/store/memory.rb', line 15

def initialize
  # The list store a simple association between sid and
  @list = Concurrent::Map.new

  # This store the index in a way that is possible to search
  # subscriptions in a fast manner
  @index = Concurrent::Map.new do |h1, key1|               # Fields
    scopes = Concurrent::Map.new do |h2, key2|             # Scopes
      arguments = Concurrent::Map.new do |h3, key3|        # Arguments
        h3.fetch_or_store(key3, Concurrent::Array.new)     # SIDs
      end

      h2.fetch_or_store(key2, arguments)
    end

    h1.fetch_or_store(key1, scopes)
  end
end

Instance Attribute Details

#indexObject (readonly)

Returns the value of attribute index.



13
14
15
# File 'lib/rails/graphql/subscription/store/memory.rb', line 13

def index
  @index
end

#listObject (readonly)

Returns the value of attribute list.



13
14
15
# File 'lib/rails/graphql/subscription/store/memory.rb', line 13

def list
  @list
end

Instance Method Details

#add(subscription) ⇒ Object



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/rails/graphql/subscription/store/memory.rb', line 47

def add(subscription)
  if has?(subscription.sid)
    raise ::ArgumentError, +"SID #{subscription.sid} is already taken."
  end

  # Rewrite the scope, to save memory
  scope = possible_scopes(subscription.scope)&.first
  subscription.instance_variable_set(:@scope, scope)

  # Save to the list and to the index
  list[subscription.sid] = subscription
  index_set = subscription_to_index(subscription).reduce(index, &:[])
  index_set << subscription.sid
  subscription.sid
end

#allObject



43
44
45
# File 'lib/rails/graphql/subscription/store/memory.rb', line 43

def all
  list.keys
end

#fetch(*sids) ⇒ Object



63
64
65
66
67
68
69
70
71
# File 'lib/rails/graphql/subscription/store/memory.rb', line 63

def fetch(*sids)
  return if sids.none?

  items = sids.map do |item|
    instance?(item) ? item : list[item]
  end

  items.one? ? items.first : items
end

#has?(item) ⇒ Boolean

Returns:

  • (Boolean)


94
95
96
# File 'lib/rails/graphql/subscription/store/memory.rb', line 94

def has?(item)
  list.key?(instance?(item) ? item.sid : item)
end

#remove(item) ⇒ Object



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/rails/graphql/subscription/store/memory.rb', line 73

def remove(item)
  return unless has?(item)

  instance = instance?(item) ? item : fetch(item)
  path = subscription_to_index(instance)
  index.delete(instance.sid)

  f_level = index[path[0]]
  s_level = f_level[path[1]]
  a_level = s_level[path[2]]

  a_level.delete(instance.sid)
  s_level.delete(path[2]) if a_level.empty?
  f_level.delete(path[1]) if s_level.empty?
  index.delete(path[0]) if f_level.empty?
end

#search(**xargs, &block) ⇒ Object Also known as: find_each



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
# File 'lib/rails/graphql/subscription/store/memory.rb', line 98

def search(**xargs, &block)
  xargs = serialize(**xargs)
  field, scope, args = xargs.values_at(:field, :scope, :args)

  if field.nil? && args.nil? && scope.nil?
    list.each(&block) unless block.nil?
    return all
  end

  [].tap do |result|
    GraphQL.enumerate(field || index.keys).each do |key1|
      GraphQL.enumerate(scope || index[key1].keys).each do |key2|
        GraphQL.enumerate(args || index[key2].keys).each do |key3|
          items = index.fetch(key1, nil)&.fetch(key2, nil)&.fetch(key3, nil)
          items.each(&list.method(:[])).each(&block) unless block.nil?
          result.concat(items || EMPTY_ARRAY)
        end
      end
    end
  end
end

#serialize(**xargs) ⇒ Object



34
35
36
37
38
39
40
41
# File 'lib/rails/graphql/subscription/store/memory.rb', line 34

def serialize(**xargs)
  return xargs if !xargs.key?(:field) || xargs[:field].is_a?(Numeric)

  xargs[:field] = hash_for(xargs[:field])
  xargs[:scope] = possible_scopes(xargs[:scope])
  xargs[:args] = Array.wrap(xargs[:args]).map(&method(:hash_for))
  xargs
end

#update!(item) ⇒ Object



90
91
92
# File 'lib/rails/graphql/subscription/store/memory.rb', line 90

def update!(item)
  (instance?(item) ? item : fetch(item)).update!
end