Welcome to mirror list, hosted at ThFree Co, Russian Federation.

dsl.rb « unnested_in_filters « lib - gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: f5f358c729e3dccc4917c3a7f0f4706e04693c06 (plain)
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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# frozen_string_literal: true

# Including the `UnnestedInFilters::Dsl` module to an ActiveRecord
# model extends the interface of the following class instances to be
# able to use the `use_unnested_filters` method;
#
#   - Model relation;
#     `Model.where(...).use_unnested_filters`
#   - All the association proxies
#     `project.model_association.use_unnested_filters`
#   - All the relation instances of the association
#     `project.model_association.where(...).use_unnested_filters
#
# Note: The interface of the model itself won't be extended as we don't
# have a use-case for now(`Model.use_unnested_filters` won't work).
#
# Example usage of the API;
#
#   relation = Vulnerabilities::Read.where(state: [1, 4])
#                                   .use_unnested_filters
#                                   .order(severity: :desc, vulnerability_id: :desc)
#
#   relation.to_a # => Will load records by using the optimized query
#
# See `UnnestedInFilters::Rewriter` for the details about the optimizations applied.
#
# rubocop:disable Gitlab/ModuleWithInstanceVariables
module UnnestedInFilters
  module Dsl
    extend ActiveSupport::Concern

    MODULES_TO_EXTEND = [
      ActiveRecord::Relation,
      ActiveRecord::Associations::CollectionProxy,
      ActiveRecord::AssociationRelation
    ].freeze

    included do
      MODULES_TO_EXTEND.each do |mod|
        delegate_mod = relation_delegate_class(mod)
        delegate_mod.prepend(UnnestedInFilters::Dsl::Relation)
      end
    end

    module Relation
      def use_unnested_filters
        spawn.use_unnested_filters!
      end

      def use_unnested_filters!
        assert_mutability!
        @values[:unnested_filters] = true

        self
      end

      def use_unnested_filters?
        @values.fetch(:unnested_filters, false)
      end

      def load(*)
        return super if loaded? || !rewrite_query?

        @records = unnested_filter_rewriter.rewrite.to_a
        @loaded = true

        self
      end

      def exists?(*)
        return super unless rewrite_query?

        unnested_filter_rewriter.rewrite.exists?
      end

      private

      def rewrite_query?
        use_unnested_filters? && unnested_filter_rewriter.rewrite?
      end

      def unnested_filter_rewriter
        @unnested_filter_rewriter ||= UnnestedInFilters::Rewriter.new(self)
      end
    end
  end
end