Class: Banzai::Filter::References::ReferenceCache

Inherits:
Object
  • Object
show all
Includes:
RequestStoreReferenceCache, Gitlab::Utils::StrongMemoize
Defined in:
lib/banzai/filter/references/reference_cache.rb

Instance Method Summary collapse

Methods included from RequestStoreReferenceCache

#cached_call, #get_or_set_cache

Constructor Details

#initialize(filter, context, result) ⇒ ReferenceCache

Returns a new instance of ReferenceCache.



10
11
12
13
14
# File 'lib/banzai/filter/references/reference_cache.rb', line 10

def initialize(filter, context, result)
  @filter = filter
  @context = context
  @result = result || {}
end

Instance Method Details

#cache_loaded?Boolean

Returns:

  • (Boolean)


170
171
172
# File 'lib/banzai/filter/references/reference_cache.rb', line 170

def cache_loaded?
  !!@cache_loaded
end

#current_parent_pathObject



145
146
147
148
149
# File 'lib/banzai/filter/references/reference_cache.rb', line 145

def current_parent_path
  strong_memoize(:current_parent_path) do
    parent&.full_path
  end
end

#current_project_namespace_pathObject



151
152
153
154
155
# File 'lib/banzai/filter/references/reference_cache.rb', line 151

def current_project_namespace_path
  strong_memoize(:current_project_namespace_path) do
    project&.namespace&.full_path
  end
end

#find_for_paths(paths) ⇒ Object

Returns projects for the given paths.



118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# File 'lib/banzai/filter/references/reference_cache.rb', line 118

def find_for_paths(paths)
  if Gitlab::SafeRequestStore.active?
    cache = refs_cache
    to_query = paths - cache.keys

    unless to_query.empty?
      records = objects_for_paths(to_query)

      found = []
      records.each do |record|
        ref = record.full_path
        get_or_set_cache(cache, ref) { record }
        found << ref
      end

      not_found = to_query - found
      not_found.each do |ref|
        get_or_set_cache(cache, ref) { nil }
      end
    end

    cache.slice(*paths).values.compact
  else
    objects_for_paths(paths)
  end
end

#full_group_path(group_ref) ⇒ Object



164
165
166
167
168
# File 'lib/banzai/filter/references/reference_cache.rb', line 164

def full_group_path(group_ref)
  return current_parent_path unless group_ref

  group_ref
end

#full_project_path(namespace, project_ref) ⇒ Object



157
158
159
160
161
162
# File 'lib/banzai/filter/references/reference_cache.rb', line 157

def full_project_path(namespace, project_ref)
  return current_parent_path unless project_ref

  namespace_ref = namespace || current_project_namespace_path
  "#{namespace_ref}/#{project_ref}"
end

#load_parent_per_referenceObject

Returns a Hash containing referenced projects grouped per their full path.



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/banzai/filter/references/reference_cache.rb', line 57

def load_parent_per_reference
  @per_reference ||= {}

  @per_reference[parent_type] ||= begin
    refs = references_per_parent.keys
    parent_ref = {}

    # if we already have a parent, no need to query it again
    refs.each do |ref|
      next unless ref

      if context[:project]&.full_path == ref
        parent_ref[ref] = context[:project]
      elsif context[:group]&.full_path == ref
        parent_ref[ref] = context[:group]
      end

      refs -= [ref] if parent_ref[ref]
    end

    find_for_paths(refs).index_by(&:full_path).merge(parent_ref)
  end
end

#load_records_per_parentObject



85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/banzai/filter/references/reference_cache.rb', line 85

def load_records_per_parent
  @_records_per_project ||= {}

  @_records_per_project[filter.object_class.to_s.underscore] ||= begin
    hash = Hash.new { |h, k| h[k] = {} }

    parent_per_reference.each do |path, parent|
      record_ids = references_per_parent[path]

      filter.parent_records(parent, record_ids).each do |record|
        hash[parent][filter.record_identifier(record)] = record
      end
    end

    hash
  end
end

#load_reference_cache(nodes) ⇒ Object



16
17
18
19
20
21
22
# File 'lib/banzai/filter/references/reference_cache.rb', line 16

def load_reference_cache(nodes)
  load_references_per_parent(nodes)
  load_parent_per_reference
  load_records_per_parent

  @cache_loaded = true
end

#load_references_per_parent(nodes) ⇒ Object

Loads all object references (e.g. issue IDs) per project/group they belong to.



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/banzai/filter/references/reference_cache.rb', line 26

def load_references_per_parent(nodes)
  @references_per_parent ||= {}

  @references_per_parent[parent_type] ||= begin
    refs = Hash.new { |hash, key| hash[key] = Set.new }

    [filter.object_class.link_reference_pattern, filter.object_class.reference_pattern].each do |pattern|
      next unless pattern

      prepare_doc_for_scan.to_enum(:scan, pattern).each do
        parent_path = if parent_type == :project
                        full_project_path($~[:namespace], $~[:project])
                      else
                        full_group_path($~[:group])
                      end

        ident = filter.identifier($~)
        refs[parent_path] << ident if ident
      end
    end

    refs
  end
end

#objects_for_paths(paths) ⇒ Object



107
108
109
110
111
112
113
114
115
# File 'lib/banzai/filter/references/reference_cache.rb', line 107

def objects_for_paths(paths)
  klass = parent_type.to_s.camelize.constantize
  result = klass.where_full_path_in(paths)
  return result if parent_type == :group
  return unless parent_type == :project

  result.includes(namespace: :route)
    .allow_cross_joins_across_databases(url: "https://gitlab.com/gitlab-org/gitlab/-/issues/420046")
end

#parent_per_referenceObject



81
82
83
# File 'lib/banzai/filter/references/reference_cache.rb', line 81

def parent_per_reference
  @per_reference[parent_type]
end

#records_per_parentObject



103
104
105
# File 'lib/banzai/filter/references/reference_cache.rb', line 103

def records_per_parent
  @_records_per_project[filter.object_class.to_s.underscore]
end

#references_per_parentObject



51
52
53
# File 'lib/banzai/filter/references/reference_cache.rb', line 51

def references_per_parent
  @references_per_parent[parent_type]
end