lib/scoped_search/definition.rb in scoped_search-3.3.0 vs lib/scoped_search/definition.rb in scoped_search-4.0.0
- old
+ new
@@ -14,48 +14,80 @@
# Instances of this class are created when calling scoped_search in your model
# class, so you should not create instances of this class yourself.
class Field
attr_reader :definition, :field, :only_explicit, :relation, :key_relation, :full_text_search,
- :key_field, :complete_value, :complete_enabled, :offset, :word_size, :ext_method, :operators
+ :key_field, :complete_value, :complete_enabled, :offset, :word_size, :ext_method, :operators,
+ :validator
# Initializes a Field instance given the definition passed to the
# scoped_search call on the ActiveRecord-based model class.
- def initialize(definition, options = {})
- @definition = definition
- @definition.profile = options[:profile] if options[:profile]
- @definition.default_order ||= default_order(options)
+ #
+ # Field name may be given in positional 'field' argument or 'on' named
+ # argument.
+ def initialize(definition,
+ field = nil,
+ aliases: [],
+ complete_enabled: true,
+ complete_value: nil,
+ default_operator: nil,
+ default_order: nil,
+ ext_method: nil,
+ full_text_search: nil,
+ in_key: nil,
+ offset: nil,
+ on: field,
+ on_key: nil,
+ only_explicit: nil,
+ operators: nil,
+ profile: nil,
+ relation: nil,
+ rename: nil,
+ validator: nil,
+ word_size: 1,
+ **kwargs)
- case options
- when Symbol, String
- @field = field.to_sym
- when Hash
- @field = options.delete(:on)
+ # Prefer 'on' kw arg if given, defaults to the 'field' positional to allow either syntax
+ raise ArgumentError, "Missing field or 'on' keyword argument" if on.nil?
+ @field = on.to_sym
- # Set attributes from options hash
- @complete_value = options[:complete_value]
- @relation = options[:in]
- @key_relation = options[:in_key]
- @key_field = options[:on_key]
- @offset = options[:offset]
- @word_size = options[:word_size] || 1
- @ext_method = options[:ext_method]
- @operators = options[:operators]
- @only_explicit = !!options[:only_explicit]
- @full_text_search = options[:full_text_search]
- @default_operator = options[:default_operator] if options.has_key?(:default_operator)
- @complete_enabled = options[:complete_enabled].nil? ? true : options[:complete_enabled]
+ # Reserved Ruby keywords so access via kwargs instead, but deprecate them for future versions
+ if kwargs.key?(:in)
+ relation = kwargs.delete(:in)
+ ActiveSupport::Deprecation.warn("'in' argument deprecated, prefer 'relation' since scoped_search 4.0.0", caller(6))
end
+ if kwargs.key?(:alias)
+ aliases += [kwargs.delete(:alias)]
+ ActiveSupport::Deprecation.warn("'alias' argument deprecated, prefer aliases: [..] since scoped_search 4.0.0", caller(6))
+ end
+ raise ArgumentError, "Unknown arguments to scoped_search: #{kwargs.keys.join(', ')}" unless kwargs.empty?
- # Store this field is the field array
- definition.fields[@field] ||= self unless options[:rename]
- definition.fields[options[:rename].to_sym] ||= self if options[:rename]
- definition.unique_fields << self
+ @definition = definition
+ @definition.profile = profile if profile
+ @definition.default_order ||= generate_default_order(default_order, rename || @field) if default_order
- # Store definition for alias / aliases as well
- definition.fields[options[:alias].to_sym] ||= self if options[:alias]
- options[:aliases].each { |al| definition.fields[al.to_sym] ||= self } if options[:aliases]
+ # Set attributes from keyword arguments
+ @complete_enabled = complete_enabled
+ @complete_value = complete_value
+ @default_operator = default_operator
+ @ext_method = ext_method
+ @full_text_search = full_text_search
+ @key_field = on_key
+ @key_relation = in_key
+ @offset = offset
+ @only_explicit = !!only_explicit
+ @operators = operators
+ @relation = relation
+ @validator = validator
+ @word_size = word_size
+
+ # Store this field in the field array
+ definition.fields[rename ? rename.to_sym : @field] ||= self
+ definition.unique_fields << self
+
+ # Store definition for aliases as well
+ aliases.each { |al| definition.fields[al.to_sym] ||= self }
end
# The ActiveRecord-based class that belongs to this field.
def klass
@klass ||= if relation
@@ -80,15 +112,11 @@
def column
@column ||= begin
if klass.columns_hash.has_key?(field.to_s)
klass.columns_hash[field.to_s]
else
- if "#{ActiveRecord::VERSION::MAJOR}.#{ActiveRecord::VERSION::MINOR}".to_f < 4.1
- raise ActiveRecord::UnknownAttributeError, "#{klass.inspect} doesn't have column #{field.inspect}."
- else
- raise ActiveRecord::UnknownAttributeError.new(klass, field)
- end
+ raise ActiveRecord::UnknownAttributeError.new(klass, field)
end
end
end
# Returns the column type of this field.
@@ -133,15 +161,13 @@
when :string, :text then :like
else :eq
end
end
- def default_order(options)
- return nil if options[:default_order].nil?
- field_name = options[:rename].nil? ? options[:on] : options[:rename]
- order = (options[:default_order].to_s.downcase.include?('desc')) ? "DESC" : "ASC"
- return "#{field_name} #{order}"
+ def generate_default_order(default_order, field)
+ order = (default_order.to_s.downcase.include?('desc')) ? "DESC" : "ASC"
+ return "#{field} #{order}"
end
# Return 'table'.'column' with the correct database quotes
def quoted_field
c = klass.connection
@@ -232,12 +258,12 @@
def default_fields
unique_fields.reject { |field| field.only_explicit }
end
# Defines a new search field for this search definition.
- def define(options)
- Field.new(self, options)
+ def define(*args)
+ Field.new(self, *args)
end
# Returns a reflection for a given klass and name
def reflection_by_name(klass, name)
return if name.nil?
@@ -250,27 +276,16 @@
def register_named_scope! # :nodoc
definition = self
@klass.scope(:search_for, proc { |query, options|
klass = definition.klass
- search_scope = case ActiveRecord::VERSION::MAJOR
- when 3
- klass.scoped
- when 4
- (ActiveRecord::VERSION::MINOR < 1) ? klass.where(nil) : klass.all
- when 5
- klass.all
- else
- raise ScopedSearch::DefinitionError, 'version ' \
- "#{ActiveRecord::VERSION::MAJOR} of activerecord is not supported"
- end
-
+ search_scope = klass.all
find_options = ScopedSearch::QueryBuilder.build_query(definition, query || '', options || {})
search_scope = search_scope.where(find_options[:conditions]) if find_options[:conditions]
search_scope = search_scope.includes(find_options[:include]) if find_options[:include]
search_scope = search_scope.joins(find_options[:joins]) if find_options[:joins]
search_scope = search_scope.reorder(find_options[:order]) if find_options[:order]
- search_scope = search_scope.references(find_options[:include]) if find_options[:include] && ActiveRecord::VERSION::MAJOR >= 4
+ search_scope = search_scope.references(find_options[:include]) if find_options[:include]
search_scope
})
end