File: descendants.rb

package info (click to toggle)
gitlab 17.6.5-19
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 629,368 kB
  • sloc: ruby: 1,915,304; javascript: 557,307; sql: 60,639; xml: 6,509; sh: 4,567; makefile: 1,239; python: 406
file content (70 lines) | stat: -rw-r--r-- 2,195 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# frozen_string_literal: true

module Namespaces
  class Descendants < ApplicationRecord
    self.table_name = :namespace_descendants

    belongs_to :namespace

    validates :namespace_id, uniqueness: true

    def self.expire_for(namespace_ids)
      # Union:
      # - Look up all parent ids including the given ids via traversal_ids
      # - Include the given ids to handle the case when the namespaces records are already deleted
      sql = <<~SQL
      WITH namespace_ids AS MATERIALIZED (
        (
          SELECT ids.id
          FROM namespaces, UNNEST(traversal_ids) ids(id)
          WHERE namespaces.id IN (?)
        ) UNION
        (SELECT UNNEST(ARRAY[?]) AS id)
      )
      UPDATE namespace_descendants SET outdated_at = ? FROM namespace_ids WHERE namespace_descendants.namespace_id = namespace_ids.id
      SQL

      connection.execute(sanitize_sql_array([sql, namespace_ids, namespace_ids, Time.current]))
    end

    def self.load_outdated_batch(batch_size)
      where
        .not(outdated_at: nil)
        .limit(batch_size)
        .lock('FOR UPDATE SKIP LOCKED')
        .pluck_primary_key
    end

    def self.upsert_with_consistent_data(namespace:, self_and_descendant_group_ids:, all_project_ids:)
      query = <<~SQL
        INSERT INTO namespace_descendants
        (namespace_id, traversal_ids, self_and_descendant_group_ids, all_project_ids, outdated_at, calculated_at)
        VALUES
        (
          ?,
          ARRAY[?]::bigint[],
          ARRAY_REMOVE(ARRAY[?]::bigint[], NULL),
          ARRAY_REMOVE(ARRAY[?]::bigint[], NULL),
          NULL,
          ?
        )
        ON CONFLICT(namespace_id)
        DO UPDATE SET
          traversal_ids = EXCLUDED.traversal_ids,
          self_and_descendant_group_ids = EXCLUDED.self_and_descendant_group_ids,
          all_project_ids = EXCLUDED.all_project_ids,
          outdated_at = EXCLUDED.outdated_at,
          calculated_at = EXCLUDED.calculated_at
      SQL

      connection.execute(sanitize_sql_array([
        query,
        namespace.id,
        namespace.traversal_ids,
        self_and_descendant_group_ids,
        all_project_ids,
        Time.current
      ]))
    end
  end
end