lib/scoped_search/definition.rb in scoped_search-2.3.7 vs lib/scoped_search/definition.rb in scoped_search-2.4.0
- old
+ new
@@ -13,42 +13,86 @@
#
# 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,
+ attr_reader :definition, :field, :only_explicit, :relation, :key_relation, :full_text_search,
:key_field, :complete_value, :offset, :word_size, :ext_method, :operators
+ # 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)
+
+ case options
+ when Symbol, String
+ @field = field.to_sym
+ when Hash
+ @field = options.delete(:on)
+
+ # 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)
+ end
+
+ # 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
+
+ # 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]
+ end
+
# The ActiveRecord-based class that belongs to this field.
def klass
- if relation
+ @klass ||= if relation
related = definition.klass.reflections[relation]
raise ScopedSearch::QueryNotSupported, "relation '#{relation}' not one of #{definition.klass.reflections.keys.join(', ')} " if related.nil?
related.klass
else
definition.klass
end
end
+
# The ActiveRecord-based class that belongs the key field in a key-value pair.
def key_klass
- if key_relation
+ @key_klass ||= if key_relation
definition.klass.reflections[key_relation].klass
elsif relation
definition.klass.reflections[relation].klass
else
definition.klass
end
end
# Returns the ActiveRecord column definition that corresponds to this field.
def column
- klass.columns_hash[field.to_s]
+ @column ||= begin
+ if klass.columns_hash.has_key?(field.to_s)
+ klass.columns_hash[field.to_s]
+ else
+ raise ActiveRecord::UnknownAttributeError, "#{klass.inspect} doesn't have column #{field.inspect}."
+ end
+ end
end
# Returns the column type of this field.
def type
- column.type
+ @type ||= column.type
end
# Returns true if this field is a datetime-like column
def datetime?
[:datetime, :time, :timestamp].include?(type)
@@ -93,45 +137,10 @@
field_name = options[:on] unless options[:rename]
field_name = options[:rename] if options[:rename]
order = (options[:default_order].to_s.downcase.include?('desc')) ? "DESC" : "ASC"
return "#{field_name} #{order}"
end
- # 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)
-
- case options
- when Symbol, String
- @field = field.to_sym
- when Hash
- @field = options.delete(:on)
-
- # 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]
- @default_operator = options[:default_operator] if options.has_key?(:default_operator)
- end
-
- # 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
-
- # 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]
- end
end
attr_reader :klass
# Initializes a ScopedSearch definition instance.
@@ -183,17 +192,19 @@
return ['= ', '> ', '< '] if field.temporal?
raise ScopedSearch::QueryNotSupported, "could not verify '#{name}' type, this can be a result of a definition error"
end
NUMERICAL_REGXP = /^\-?\d+(\.\d+)?$/
+ INTEGER_REGXP = /^\-?\d+$/
# Returns a list of appropriate fields to search in given a search keyword and operator.
def default_fields_for(value, operator = nil)
column_types = []
column_types += [:string, :text] if [nil, :like, :unlike, :ne, :eq].include?(operator)
- column_types += [:integer, :double, :float, :decimal] if value =~ NUMERICAL_REGXP
+ column_types += [:double, :float, :decimal] if value =~ NUMERICAL_REGXP
+ column_types += [:integer] if value =~ INTEGER_REGXP
column_types += [:datetime, :date, :timestamp] if (parse_temporal(value))
default_fields.select { |field| column_types.include?(field.type) && !field.set? }
end
@@ -234,28 +245,26 @@
find_options = ScopedSearch::QueryBuilder.build_query(self, args[0], args[1])
search_scope = @klass.scoped
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.order(find_options[:order]) if find_options[:order]
- search_scope = search_scope.group(find_options[:group]) if find_options[:group]
+ search_scope = search_scope.reorder(find_options[:order]) if find_options[:order]
search_scope
})
else
raise "This ActiveRecord version is currently not supported!"
end
else
raise "Currently, only ActiveRecord 2.1 or higher is supported!"
end
end
- end
-end
-# Registers the complete_for method within the class that is used for searching.
- def register_complete_for! # :nodoc
-@klass.class_eval do
- def self.complete_for (query, options = {})
- search_options = ScopedSearch::AutoCompleteBuilder.auto_complete(@scoped_search , query, options)
- search_options
+ # Registers the complete_for method within the class that is used for searching.
+ def register_complete_for! # :nodoc
+ @klass.class_eval do
+ def self.complete_for(query, options = {})
+ ScopedSearch::AutoCompleteBuilder.auto_complete(@scoped_search , query, options)
+ end
+ end
end
end
- end
+end