Class: ParamsReady::Query::Relation

Inherits:
StructuredGrouping show all
Extended by:
Forwardable, PageAccessors
Defined in:
lib/params_ready/query/relation.rb

Defined Under Namespace

Modules: PageAccessors

Constant Summary

Constants inherited from Parameter::AbstractStructParameter

Parameter::AbstractStructParameter::EMPTY_HASH

Instance Attribute Summary

Attributes inherited from Parameter::AbstractParameter

#definition

Instance Method Summary collapse

Methods included from PageAccessors

extended, page_accessor

Methods inherited from StructuredGrouping

#context_for_predicates, #operator, #predicates

Methods included from Parameter::GroupingLike

#eligible_for_query?, #predicate_group, #test, #to_query

Methods included from Marshaller::ParameterModule

#marshal

Methods inherited from Parameter::AbstractStructParameter

#[], #[]=, #find_in_hash, #for_frontend, #for_model, #for_output, #wrap_output

Methods included from Parameter::ComplexParameter

#update_child

Methods inherited from Parameter::Parameter

#allows_undefined?, #definite_default?, #eligible_for_output?, #find_in_hash, #format, #format_self_permitted, #freeze, #hash, #hash_key, #initialize, #inspect_content, #is_default?, #is_definite?, #is_nil?, #is_undefined?, #memo, #memo!, #nil_default?, #populate_other, #set_from_input, #set_value, #to_hash_if_eligible, #unwrap, #unwrap_or, #wrap_output

Methods inherited from Parameter::AbstractParameter

#==, #dup, #initialize, #inspect, intent_for_children, #match?, #populate, #to_hash, #update_if_applicable, #update_in

Methods included from Extensions::Freezer

#freeze_variable, #freeze_variables, #variables_to_freeze

Methods included from Parameter::FromHash

#set_from_hash

Methods included from Extensions::Freezer::InstanceMethods

#freeze

Constructor Details

This class inherits a constructor from ParamsReady::Parameter::Parameter

Instance Method Details

#after_page(keyset) ⇒ Object



108
109
110
111
# File 'lib/params_ready/query/relation.rb', line 108

def after_page(keyset)
  tuple = { direction: :aft, limit: limit, keyset: keyset }
  update_in(tuple, [:pagination])
end

#arel_table(default_model_class) ⇒ Object



133
134
135
# File 'lib/params_ready/query/relation.rb', line 133

def arel_table(default_model_class)
  model_class(default_model_class).arel_table
end

#before_page(keyset) ⇒ Object



103
104
105
106
# File 'lib/params_ready/query/relation.rb', line 103

def before_page(keyset)
  tuple = { direction: :bfr, limit: limit, keyset: keyset }
  update_in(tuple, [:pagination])
end

#build_keyset_query(limit, direction, keyset, model_class: nil, context: Restriction.blanket_permission) ⇒ Object



198
199
200
201
# File 'lib/params_ready/query/relation.rb', line 198

def build_keyset_query(limit, direction, keyset, model_class: nil, context: Restriction.blanket_permission)
  arel_table, query = build_query(model_class, context)
  pagination.select_keysets(query, limit, direction, keyset, ordering, arel_table, context)
end

#build_query(model_class, context) ⇒ Object



203
204
205
206
207
208
209
210
211
212
213
214
215
216
# File 'lib/params_ready/query/relation.rb', line 203

def build_query(model_class, context)
  arel_table = arel_table(model_class)

  group = to_query_if_eligible(arel_table, context: context)
  joined = joined_tables(arel_table, context)

  query = if group.nil?
    joined
  else
    joined.where(group)
  end

  [arel_table, query]
end

#build_relation(scope: nil, include: [], context: Restriction.blanket_permission, paginate: true) ⇒ Object



157
158
159
160
161
162
163
164
165
# File 'lib/params_ready/query/relation.rb', line 157

def build_relation(scope: nil, include: [], context: Restriction.blanket_permission, paginate: true)
  model_class = scope || definition.model_class
  group = to_query_if_eligible(model_class.arel_table, context: context)
  relation = model_class.where(group)
  relation = relation.includes(*include) unless include.empty?
  relation = perform_joins(relation, context)

  order_and_paginate_relation(relation, context, paginate)
end

#build_select(model_class: nil, context: Restriction.blanket_permission, select_list: Arel.star, paginate: true) ⇒ Object



192
193
194
195
196
# File 'lib/params_ready/query/relation.rb', line 192

def build_select(model_class: nil, context: Restriction.blanket_permission, select_list: Arel.star, paginate: true)
  arel_table, query = build_query(model_class, context)
  query = order_and_paginate_query(query, arel_table, context, paginate)
  query.project(select_list)
end

#child_is_definite?(name) ⇒ Boolean

Returns:

  • (Boolean)


41
42
43
44
45
46
47
# File 'lib/params_ready/query/relation.rb', line 41

def child_is_definite?(name)
  return false unless definition.has_child?(name)
  return false if self[name].nil?
  return false unless self[name].is_definite?

  true
end

#current_page(count: nil) ⇒ Object



76
77
78
# File 'lib/params_ready/query/relation.rb', line 76

def current_page(count: nil)
  page(0, count: count)
end

#first_pageObject



80
81
82
83
# File 'lib/params_ready/query/relation.rb', line 80

def first_page
  value = pagination.first_page_value
  update_in(value, [:pagination])
end

#join_tables(joins, base_table, context) ⇒ Object



264
265
266
267
268
269
270
271
# File 'lib/params_ready/query/relation.rb', line 264

def join_tables(joins, base_table, context)
  joins.reduce(base_table) do |joined_table, join|
    join = join.to_arel(joined_table, base_table, context, self)
    next joined_table if join.nil?

    join
  end
end

#joined_tables(base_table, context) ⇒ Object



260
261
262
# File 'lib/params_ready/query/relation.rb', line 260

def joined_tables(base_table, context)
  join_tables(definition.joins, base_table, context)
end

#keysets(limit, direction, keyset, scope: nil, context: Restriction.blanket_permission, &block) ⇒ Object



145
146
147
148
149
150
151
152
153
154
155
# File 'lib/params_ready/query/relation.rb', line 145

def keysets(limit, direction, keyset, scope: nil, context: Restriction.blanket_permission, &block)
  model_class = scope || definition.model_class
  group = to_query_if_eligible(model_class.arel_table, context: context)
  relation = model_class.where(group)
  relation = perform_joins(relation, context)

  sql_literal = pagination.keysets_for_relation(relation, limit, direction, keyset, ordering, context, &block)

  array = model_class.connection.execute(sql_literal.to_s).to_a
  Pagination::Direction.instance(direction).keysets(keyset, array, &block)
end

#last_page(count:) ⇒ Object



85
86
87
88
89
# File 'lib/params_ready/query/relation.rb', line 85

def last_page(count:)
  value = pagination.last_page_value(count: count)
  return if value.nil?
  update_in(value, [:pagination])
end

#limited_at(limit) ⇒ Object



113
114
115
# File 'lib/params_ready/query/relation.rb', line 113

def limited_at(limit)
  update_in(limit, [:pagination, pagination.limit_key])
end

#model_class(default_model_class) ⇒ Object



129
130
131
# File 'lib/params_ready/query/relation.rb', line 129

def model_class(default_model_class)
  default_model_class || definition.model_class
end

#new_offset(delta) ⇒ Object



63
64
65
# File 'lib/params_ready/query/relation.rb', line 63

def new_offset(delta)
  pagination.new_offset(delta)
end

#next_page(delta = 1, count: nil) ⇒ Object



97
98
99
100
101
# File 'lib/params_ready/query/relation.rb', line 97

def next_page(delta = 1, count: nil)
  value = pagination.next_page_value(delta, count: count)
  return if value.nil?
  page(delta, count: count)
end

#order_and_paginate_query(query, arel_table, context, paginate) ⇒ Object



249
250
251
252
253
254
255
256
257
258
# File 'lib/params_ready/query/relation.rb', line 249

def order_and_paginate_query(query, arel_table, context, paginate)
  paginate_if_applicable(paginate) do |pagination|
    query = pagination.paginate_query(query, ordering_or_nil, arel_table, context)
  end

  order_if_applicable(arel_table, context) do |ordering|
    query = query.order(*ordering)
  end
  query
end

#order_and_paginate_relation(relation, context, paginate) ⇒ Object



238
239
240
241
242
243
244
245
246
247
# File 'lib/params_ready/query/relation.rb', line 238

def order_and_paginate_relation(relation, context, paginate)
  paginate_if_applicable(paginate) do |pagination|
    relation = pagination.paginate_relation(relation, ordering_or_nil, context)
  end

  order_if_applicable(relation.arel_table, context) do |ordering|
    relation = relation.order(ordering)
  end
  relation
end

#order_if_applicable(arel_table, context) ⇒ Object



224
225
226
227
228
229
# File 'lib/params_ready/query/relation.rb', line 224

def order_if_applicable(arel_table, context)
  if child_is_definite?(:ordering) && (context.permitted?(ordering) || ordering.required?)
    ordering = self.ordering.to_arel(arel_table, context: context)
    yield ordering if ordering.length > 0
  end
end

#orderingObject



53
54
55
# File 'lib/params_ready/query/relation.rb', line 53

def ordering
  self[:ordering]
end

#ordering_or_nilObject



57
58
59
60
61
# File 'lib/params_ready/query/relation.rb', line 57

def ordering_or_nil
  return unless child_is_definite?(:ordering)

  self[:ordering]
end

#page(delta, count: nil) ⇒ Object



67
68
69
70
71
72
73
74
# File 'lib/params_ready/query/relation.rb', line 67

def page(delta, count: nil)
  return nil unless pagination.can_yield_page?(delta, count: count)
  return self if delta == 0

  new_offset = pagination.new_offset(delta)

  update_in(new_offset, [:pagination, 0])
end

#paginate_if_applicable(paginate) ⇒ Object



231
232
233
234
235
236
# File 'lib/params_ready/query/relation.rb', line 231

def paginate_if_applicable(paginate)
  if paginate && child_is_definite?(:pagination)
    pagination = self.pagination
    yield pagination
  end
end

#paginationObject



49
50
51
# File 'lib/params_ready/query/relation.rb', line 49

def pagination
  self[:pagination]
end

#perform_count(scope: nil, context: Restriction.blanket_permission) ⇒ Object



137
138
139
140
141
142
143
# File 'lib/params_ready/query/relation.rb', line 137

def perform_count(scope: nil, context: Restriction.blanket_permission)
  scope ||= definition.model_class if definition.model_class_defined?
  group = to_query_if_eligible(scope.arel_table, context: context)
  relation = scope.where(group)
  relation = perform_joins(relation, context)
  relation.count
end

#perform_joins(relation, context) ⇒ Object



167
168
169
170
171
172
173
174
175
# File 'lib/params_ready/query/relation.rb', line 167

def perform_joins(relation, context)
  eligible_joins = definition.joins.select do |join|
    join.eligible?(context, self)
  end
  return relation if eligible_joins.empty?

  sql = join_tables(eligible_joins, relation.arel_table, context).join_sources.map(&:to_sql).join(' ')
  relation.joins(sql)
end

#previous_page(delta = 1) ⇒ Object



91
92
93
94
95
# File 'lib/params_ready/query/relation.rb', line 91

def previous_page(delta = 1)
  value = pagination.previous_page_value(delta)
  return if value.nil?
  update_in(value, [:pagination])
end

#reordered(column, direction) ⇒ Object



123
124
125
126
127
# File 'lib/params_ready/query/relation.rb', line 123

def reordered(column, direction)
  new_order = ordering.reordered_value(column, direction)
  reordered = update_in(new_order, [:ordering])
  reordered.update_in(0, [:pagination, 0])
end

#to_count(model_class: nil, context: Restriction.blanket_permission) ⇒ Object



177
178
179
180
181
182
183
184
185
186
187
188
189
190
# File 'lib/params_ready/query/relation.rb', line 177

def to_count(model_class: nil, context: Restriction.blanket_permission)
  model_class = model_class || definition.model_class

  arel_table = joined_tables(model_class.arel_table, context)

  group = to_query_if_eligible(model_class.arel_table, context: context)

  query = if group.nil?
    arel_table
  else
    arel_table.where(group)
  end
  query.project(arel_table[:id].count)
end

#to_query_if_eligible(arel_table, context:) ⇒ Object



218
219
220
221
222
# File 'lib/params_ready/query/relation.rb', line 218

def to_query_if_eligible(arel_table, context:)
  return if respond_to?(:to_query?) && !to_query?(arel_table, context)

  predicate_group(arel_table, context: context)
end

#toggled_order(column) ⇒ Object



117
118
119
120
121
# File 'lib/params_ready/query/relation.rb', line 117

def toggled_order(column)
  new_order = ordering.toggled_order_value(column)
  toggled = update_in(new_order, [:ordering])
  toggled.update_in(0, [:pagination, 0])
end