Sha256: 847709c48b2503eb3ba0905f71f1247bce0a73746ad894ce6875353b571c00b4

Contents?: true

Size: 1.5 KB

Versions: 5

Compression:

Stored size: 1.5 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 Naming/MethodName
      def visit_Lipstick_Filterable_CollatedArelAttribute(object, collector)
        visit(object.attribute, collector)
        collector << ' COLLATE ' << object.collation
      end
      # rubocop:enable Naming/MethodName
    end

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

    module ClassMethods
      attr_reader :filterable_fields

      def filterable_by(*fields)
        @filterable_fields = fields
      end

      def filterable_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-4.4.0 lib/lipstick/filterable.rb
aaf-lipstick-4.3.0 lib/lipstick/filterable.rb
aaf-lipstick-4.2.0 lib/lipstick/filterable.rb
aaf-lipstick-4.1.0 lib/lipstick/filterable.rb
aaf-lipstick-4.0.1 lib/lipstick/filterable.rb