Sha256: 4b5c8ef73f734eb975c77641059c3e95551f3e7cafacfccbae878aa2a448c2e0

Contents?: true

Size: 1.49 KB

Versions: 5

Compression:

Stored size: 1.49 KB

Contents

# frozen_string_literal: true

module Lipstick
  module Filterable
    # Provides case-insensitive matching on a case-sensitive MySQL database
    # (which is mandated by Gumboot)
    class CollatedArelAttribute < Arel::Nodes::Node
      include Arel::Predications

      attr_reader :attribute, :collation

      def initialize(attribute, collation)
        @attribute = attribute
        @collation = collation
      end
    end

    module VisitCollatedArelAttribute
      # rubocop:disable Style/MethodName
      def visit_Lipstick_Filterable_CollatedArelAttribute(object, collector)
        visit(object.attribute, collector)
        collector << ' COLLATE ' << object.collation
      end
      # rubocop:enable Style/MethodName
    end

    Arel::Visitors::ToSql.include(VisitCollatedArelAttribute)

    module ClassMethods
      attr_reader :filterable_fields

      def filterable_by(*fields)
        @filterable_fields = fields
      end

      def filter(query)
        filter_terms(query).reduce(all) do |scope, term|
          conds = filterable_fields.map do |f|
            CollatedArelAttribute.new(arel_table[f], 'utf8_unicode_ci')
                                 .matches(term)
          end
          scope.where(conds.reduce { |acc, elem| acc.or(elem) })
        end
      end

      private

      def filter_terms(query)
        query.to_s.downcase.split(/\s+/).map { |s| "*#{s}*".gsub(/[%*]+/, '%') }
      end
    end

    def self.included(base)
      base.extend(ClassMethods)
    end
  end
end

Version data entries

5 entries across 5 versions & 1 rubygems

Version Path
aaf-lipstick-3.2.0 lib/lipstick/filterable.rb
aaf-lipstick-3.1.0 lib/lipstick/filterable.rb
aaf-lipstick-3.0.6 lib/lipstick/filterable.rb
aaf-lipstick-3.0.5 lib/lipstick/filterable.rb
aaf-lipstick-3.0.4 lib/lipstick/filterable.rb