Method: Effective::Resources::Relation#search_attribute

Defined in:
app/models/effective/resources/relation.rb

#search_attribute(name, value, as:, operation:, sql_column:) ⇒ Object



277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
# File 'app/models/effective/resources/relation.rb', line 277

def search_attribute(name, value, as:, operation:, sql_column:)
  raise 'expected relation to be present' unless relation

  attribute = relation.arel_table[name]

  # Normalize the term.
  # If you pass an email attribute it can return nil so we return the full value
  term = Attribute.new(as).parse(value, name: name)
  term = value if term.nil?

  # If using the joined syntax from datatables
  joined = (sql_column.to_s.split('.').first.to_s.include?(relation.arel_table.name) == false)

  searched = case as
    when :active_storage
      relation.send("with_attached_#{name}").references("#{name}_attachment")
        .where(ActiveStorage::Blob.arel_table[:filename].matches("%#{term}%"))

    when :date, :datetime
      if value.kind_of?(String)
        end_at = (
          case (value.to_s.scan(/(\d+)/).flatten).length
          when 1 ; term.end_of_year     # Year
          when 2 ; term.end_of_month    # Year-Month
          when 3 ; term.end_of_day      # Year-Month-Day
          when 4 ; term.end_of_hour     # Year-Month-Day Hour
          when 5 ; term.end_of_minute   # Year-Month-Day Hour-Minute
          when 6 ; term + 1.second      # Year-Month-Day Hour-Minute-Second
          else term
          end
        )

        if as == :date
          term = term.to_date
          end_at = end_at.to_date
        end

        relation.where("#{sql_column} >= ? AND #{sql_column} <= ?", term, end_at)
      elsif value.respond_to?(:strftime) && operation == :eq
        relation.where(attribute.matches(value))
      end

    when :effective_obfuscation
      term = Attribute.new(as, klass: (associated(name).try(:klass) || klass)).parse(value, name: name)
      relation.where(attribute.eq((value == term ? 0 : term)))

    when :effective_addresses
      association = associated(name)
      associated = Resource.new(association).search_any(value)
      relation.where(id: associated.where(addressable_type: klass.name).select(:addressable_id))

    when :effective_roles
      relation.with_role(term)

    when :time
      timed = relation.where("EXTRACT(hour from #{sql_column}) = ?", term.utc.hour)
      timed = timed.where("EXTRACT(minute from #{sql_column}) = ?", term.utc.min) if term.min > 0
      timed
  end

  return searched if searched

  # Simple operation search
  # The Arel operator eq and matches bug out with serialized Array columns. So we avoid for datatables usage.

  case operation
    when :eq then relation.where("#{sql_column} = ?", term)
    when :matches then relation.where("#{sql_column} #{ilike} ?", "%#{term}%")
    when :not_eq then relation.where(attribute.not_eq(term))
    when :does_not_match then relation.where(attribute.does_not_match("%#{term}%"))
    when :starts_with then relation.where(attribute.matches("#{term}%"))
    when :ends_with then relation.where(attribute.matches("%#{term}"))
    when :gt then relation.where(attribute.gt(term))
    when :gteq then relation.where(attribute.gteq(term))
    when :lt then relation.where(attribute.lt(term))
    when :lteq then relation.where(attribute.lteq(term))
    else raise("Unexpected operation: #{operation}")
  end
end