Class: Plutonium::Resource::QueryObject

Inherits:
Object
  • Object
show all
Defined in:
lib/plutonium/resource/query_object.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(resource_class, params, request_path) {|_self| ... } ⇒ QueryObject

Initializes a QueryObject with the given resource_class and parameters.

Parameters:

  • resource_class (Object)

    The resource class.

  • params (Hash)

    The parameters for initialization.

Yields:

  • (_self)

Yield Parameters:



11
12
13
14
15
16
17
18
19
20
# File 'lib/plutonium/resource/query_object.rb', line 11

def initialize(resource_class, params, request_path, &)
  @resource_class = resource_class
  @params = params
  @request_path = request_path

  define_standard_queries
  yield self if block_given?
  extract_filter_params
  extract_sort_params
end

Instance Attribute Details

#default_scope_nameObject

Returns the value of attribute default_scope_name.



5
6
7
# File 'lib/plutonium/resource/query_object.rb', line 5

def default_scope_name
  @default_scope_name
end

#default_sort_configObject

Returns the value of attribute default_sort_config.



5
6
7
# File 'lib/plutonium/resource/query_object.rb', line 5

def default_sort_config
  @default_sort_config
end

#search_filterObject (readonly)

Returns the value of attribute search_filter.



4
5
6
# File 'lib/plutonium/resource/query_object.rb', line 4

def search_filter
  @search_filter
end

#search_queryObject (readonly)

Returns the value of attribute search_query.



4
5
6
# File 'lib/plutonium/resource/query_object.rb', line 4

def search_query
  @search_query
end

Instance Method Details

#active_filter_descriptionsObject

Returns an array of hashes describing each currently active filter. Each hash has: name, label, value_label, clear_url



145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'lib/plutonium/resource/query_object.rb', line 145

def active_filter_descriptions
  filter_definitions.filter_map do |name, filter|
    name = name.to_sym
    filter_params = params[name]
    next unless filter_params.present?

    value_label = case filter_params
    when Hash, ActionController::Parameters
      entries = filter_params.to_h.reject { |_, v| v.blank? }
      next if entries.empty?
      # Single-input filters defer to the filter's `humanize_value`
      # (e.g. Association resolves ids to labels, Boolean translates
      # "true" -> "Yes"). Multi-input filters keep input-name
      # qualifiers (e.g. "from 2024, to 2025").
      if entries.size == 1
        humanized = filter.humanize_value(entries.values.first)
        next if humanized.blank?
        humanized
      else
        entries.map { |k, v| "#{k.to_s.humanize.downcase} #{v}" }.join(", ")
      end
    when Array
      entries = filter_params.reject(&:blank?)
      next if entries.empty?
      humanized = filter.humanize_value(entries)
      next if humanized.blank?
      humanized
    else
      next if filter_params.to_s.blank?
      humanized = filter.humanize_value(filter_params)
      next if humanized.blank?
      humanized
    end

    {
      name: name,
      label: name.to_s.humanize,
      value_label: value_label,
      clear_url: build_url(name => nil)
    }
  end
end

#all_scope_selected?Boolean

Returns true if user explicitly selected “All” scope (no filtering)

Returns:

  • (Boolean)


134
# File 'lib/plutonium/resource/query_object.rb', line 134

def all_scope_selected? = @all_scope_selected

#apply(scope, params, context: nil) ⇒ Object

Applies the defined filters and sorts to the given scope.

Parameters:

  • scope (Object)

    The initial scope to which filters and sorts are applied.

  • params (Hash)

    The query parameters.

  • context (Object) (defaults to: nil)

    Optional context (e.g., controller) for executing scope blocks.

Returns:

  • (Object)

    The modified scope.



111
112
113
114
115
116
117
118
119
# File 'lib/plutonium/resource/query_object.rb', line 111

def apply(scope, params, context: nil)
  params = deep_compact(params.with_indifferent_access)
  scope = search_filter.apply(scope, search: params[:search]) if search_filter && params[:search]
  # Use selected_scope which includes the default when no explicit selection
  effective_scope = @selected_scope_filter
  scope = scope_definitions[effective_scope].apply(scope, context:) if effective_scope && scope_definitions[effective_scope]
  scope = apply_sorts(scope, params)
  apply_filters(scope, params)
end

#build_url(**options) ⇒ String

Builds a URL with the given options for search and sorting.

Parameters:

  • options (Hash)

    The options for building the URL.

Options Hash (**options):

  • :replace (Boolean)

    When true, clears all existing sorts before applying the new one

Returns:

  • (String)

    The constructed URL with query parameters.



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/plutonium/resource/query_object.rb', line 70

def build_url(**options)
  q = {}

  q[:search] = options.key?(:search) ? options[:search].presence : search_query
  q[:scope] = if options.key?(:scope)
    options[:scope].presence
  else
    selected_scope_filter
  end

  if options.delete(:replace)
    q[:sort_directions] = {}
    q[:sort_fields] = []
  else
    q[:sort_directions] = selected_sort_directions.dup
    q[:sort_fields] = selected_sort_fields.dup
  end
  handle_sort_options!(q, options)

  filter_keys = filter_definitions.keys.map(&:to_sym)
  filter_overrides = options.slice(*filter_keys).stringify_keys
  q.merge! params.with_indifferent_access.slice(*filter_definitions.keys)
  q.merge!(filter_overrides)
  compacted = deep_compact({q: q})

  # Preserve explicit "All" selection (scope: nil in options means show all)
  if options.key?(:scope) && options[:scope].nil?
    compacted[:q] ||= {}
    compacted[:q][:scope] = ""
  end

  query_params = compacted.to_param
  "#{@request_path}?#{query_params}"
end

#define_filter(name, body) ⇒ Object

Defines a filter with the given name and body.

Parameters:

  • name (Symbol)

    The name of the filter.

  • body (Proc, nil)

    The body of the filter.



26
27
28
# File 'lib/plutonium/resource/query_object.rb', line 26

def define_filter(name, body, &)
  filter_definitions[name] = build_query(body, &)
end

#define_scope(name, body = nil, condition: nil) ⇒ Object

Defines a scope with the given name and body.

Parameters:

  • name (Symbol)

    The name of the scope.

  • body (Proc, nil) (defaults to: nil)

    The body of the scope.

  • condition (Proc, nil) (defaults to: nil)

    Display-only visibility gate (same semantics as condition: on actions).



35
36
37
38
39
# File 'lib/plutonium/resource/query_object.rb', line 35

def define_scope(name, body = nil, condition: nil, **)
  body ||= name
  scope_definitions[name] = build_query(body)
  scope_conditions[name] = condition if condition
end

#define_search(body) ⇒ Object

Defines a search filter with the given body.

Parameters:

  • body (Proc, Symbol)

    The body of the search filter.



59
60
61
62
63
# File 'lib/plutonium/resource/query_object.rb', line 59

def define_search(body)
  @search_filter = build_query(body) do |query|
    query.input :search
  end
end

#define_sorter(name, body = nil, using: nil) ⇒ Object

Defines a sort with the given name and body.

Parameters:

  • name (Symbol)

    The name of the sort.

  • body (Proc, nil) (defaults to: nil)

    The body of the sort.



45
46
47
48
49
50
51
52
53
54
# File 'lib/plutonium/resource/query_object.rb', line 45

def define_sorter(name, body = nil, using: nil)
  if body.nil?
    sort_field = using || determine_sort_field(name)
    body = ->(scope, direction:) { scope.order(sort_field => direction) }
  end

  sort_definitions[name] = build_query(body) do |query|
    query.input :direction
  end
end

#filter_definitionsObject



139
# File 'lib/plutonium/resource/query_object.rb', line 139

def filter_definitions = @filter_definitions ||= {}.with_indifferent_access

#scope_conditionsObject



123
# File 'lib/plutonium/resource/query_object.rb', line 123

def scope_conditions = @scope_conditions ||= {}.with_indifferent_access

#scope_definitionsObject



121
# File 'lib/plutonium/resource/query_object.rb', line 121

def scope_definitions = @scope_definitions ||= {}.with_indifferent_access

#scope_visible?(name, view_context) ⇒ Boolean

Display-only visibility gate for a scope, mirroring condition: on actions. Returns true when no condition is set.

Returns:

  • (Boolean)


127
128
129
130
131
# File 'lib/plutonium/resource/query_object.rb', line 127

def scope_visible?(name, view_context)
  condition = scope_conditions[name]
  return true if condition.nil?
  Plutonium::Action::ConditionContext.new(view_context, nil).instance_exec(&condition)
end

#selected_scopeObject

Returns the currently selected scope (may be default if none explicitly selected)



137
# File 'lib/plutonium/resource/query_object.rb', line 137

def selected_scope = @selected_scope_filter

#sort_definitionsObject



141
# File 'lib/plutonium/resource/query_object.rb', line 141

def sort_definitions = @sort_definitions ||= {}.with_indifferent_access

#sort_params_for(name) ⇒ Hash?

Provides sorting parameters for the given field name.

Parameters:

  • name (Symbol, String)

    The name of the field to sort.

Returns:

  • (Hash, nil)

    The sorting parameters including URL, multi_url, direction, position and multi flag.



192
193
194
195
196
197
198
199
200
201
202
203
204
205
# File 'lib/plutonium/resource/query_object.rb', line 192

def sort_params_for(name)
  return unless sort_definitions[name]

  multi = selected_sort_fields.size > 1 && selected_sort_fields.include?(name.to_s)

  {
    url: build_url(sort: name, replace: true),
    multi_url: build_url(sort: name),
    reset_url: build_url(sort: name, reset: true),
    position: selected_sort_fields.index(name.to_s),
    direction: selected_sort_directions[name],
    multi: multi
  }
end