search.rb 1.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. class Service::Search < Service::BaseWithCurrentUser
  3. Result = Struct.new(:result, :sorting) do
  4. def flattened
  5. result
  6. .in_order_of(:first, sorting)
  7. .flat_map { |elem| elem.last[:objects] }
  8. end
  9. end
  10. attr_reader :query, :objects, :options
  11. # @param current_user [User] which runs the search
  12. # @param query [String] to search for
  13. # @param objects [Array<ActiveRecord::Base>] searchable classes with search_preferences method present
  14. # @param options [Hash] options to forward to CanSearch and SearchIndexBackend. E.g. offset and limit.
  15. def initialize(current_user:, query:, objects:, options: {})
  16. super(current_user:)
  17. @query = query
  18. @objects = objects
  19. @options = options
  20. .compact_blank
  21. .with_defaults(limit: 10) # limit can be overriden
  22. .merge!(with_total_count: true, full: true) # those options are mandatory
  23. end
  24. def execute
  25. result = models_sorted
  26. .index_with { |elem| search_single_model(elem) }
  27. .compact
  28. Result.new(result, models_sorted)
  29. end
  30. private
  31. def models
  32. @models ||= objects
  33. .index_with { |elem| elem.search_preferences(current_user) }
  34. .compact_blank
  35. end
  36. def models_sorted
  37. @models_sorted ||= models.keys.sort_by { |elem| models.dig(elem, :prio) }.reverse
  38. end
  39. def search_single_model(model)
  40. if !SearchIndexBackend.enabled? || !models.dig(model, :direct_search_index)
  41. return model.search(query:, current_user:, **options)
  42. end
  43. SearchIndexBackend
  44. .search_by_index(query, model.name, options)
  45. .tap do |result|
  46. next if result.blank?
  47. result[:objects] = result[:object_metadata]
  48. .map { |elem| model.lookup(id: elem[:id]) }
  49. end
  50. end
  51. end