diff --git a/README.markdown b/README.markdown index c84b107..cd2a3a2 100644 --- a/README.markdown +++ b/README.markdown @@ -27,6 +27,10 @@ Adds support for [“more like this”](http://www.elasticsearch.org/guide/refer Adds support for [“fuzzy like this”](http://www.elasticsearch.org/guide/reference/query-dsl/flt-query.html) queries. +### Regular Expression Queries ### + +Adds support for [“regexp”](http://www.elasticsearch.org/guide/reference/query-dsl/regexp-query/) queries. + ### Custom Filters Score ### Adds support for [“custom filters score”](http://www.elasticsearch.org/guide/reference/query-dsl/custom-filters-score-query.html) queries. diff --git a/lib/tire/queries/regexp.rb b/lib/tire/queries/regexp.rb new file mode 100644 index 0000000..1fe5236 --- /dev/null +++ b/lib/tire/queries/regexp.rb @@ -0,0 +1,46 @@ +# Regexp +# ============== +# +# Author: Curtis Hatter +# +# +# Adds support for "regexp" queries in Tire DSL. +# +# It hooks into the Query class and inserts the regexp query type. +# +# +# Usage: +# ------ +# +# Require the component: +# +# require 'tire/queries/regexp' +# +# From that point on you should have the regexp query available. +# +# +# Example: +# ------- +# +# Tire.search 'articles' do +# query do +# regexp "name.first", 's.*y' +# end +# end +# +# Tire.search 'articles' do +# query do +# regexp "name.first", 's.*y', boost: 1.2, flags: [:intersection, :complement, :empty] +# end +# end +# +# For more about this query: +# +# * +# +# +require 'tire/queries/regexp/regexp' + +Tire::Search::Query.class_eval do + include Tire::Search::Regexp +end diff --git a/lib/tire/queries/regexp/regexp.rb b/lib/tire/queries/regexp/regexp.rb new file mode 100644 index 0000000..c77d3af --- /dev/null +++ b/lib/tire/queries/regexp/regexp.rb @@ -0,0 +1,30 @@ +module Tire + module Search + module Regexp + def regexp(field, text, options = {}) + @value = {:regexp => { field => { value: text } } } + @value[:regexp][field].update(validate_regexp_options(options)) + @value + end + + private + def validate_regexp_options(options) + valid_options = [:boost, :flags] + options.delete_if { |key, value| !valid_options.member? key } + + options[:flags] = validate_regexp_flags(options[:flags]) if options.member?(:flags) + options + end + + def validate_regexp_flags(flags = []) + valid_flags = [:all, :anystring, :automaton, :complement, :empty, :intersection, :interval, :none] + + if flags.is_a?(Array) + (flags.map { |i| i.downcase.to_sym } & valid_flags).map { |i| i.to_s.upcase }.join('|') + else + flags.to_s.upcase if valid_flags.member?(flags) + end + end + end + end +end diff --git a/test/queries/regexp/regexp_test.rb b/test/queries/regexp/regexp_test.rb new file mode 100644 index 0000000..1cedbd2 --- /dev/null +++ b/test/queries/regexp/regexp_test.rb @@ -0,0 +1,45 @@ +require 'tire' +require 'tire/queries/regexp' +require 'shoulda' + +module Tire + module Search + class RegexpTest < Test::Unit::TestCase + + context "Regexp queries" do + should "search for documents that have fields matching a regular expression" do + assert_equal({:regexp => {'name.first' => { :value => 's.*y'}}}, Query.new.regexp('name.first', 's.*y')) + end + + should "allow to boost a regexp query" do + assert_equal({:regexp => {'name.first' => { :value => 's.*y', :boost => 2.0}}}, + Query.new.regexp("name.first", 's.*y', :boost => 2.0)) + end + + should "allow to use special flags" do + assert_equal({:regexp => {'name.first' => { :value => 's.*y', :flags => 'INTERSECTION|COMPLEMENT|EMPTY'}}}, + Query.new.regexp('name.first', 's.*y', :flags => [:intersection, :complement, :empty])) + end + + should "allow to pass in only one flag" do + assert_equal({:regexp => {'name.first' => { :value => 's.*y', :flags => 'ALL' }}}, + Query.new.regexp('name.first', 's.*y', :flags => :all)) + end + end + + context "validate the options passed" do + should "drop all the invalid keys" do + assert_equal({:regexp => {'name.first' => {:value => 's.*y', :boost => 2.0}}}, + Query.new.regexp('name.first', 's.*y', :boost => 2.0, :foo => :bar)) + assert_equal({:regexp => {'name.first' => {:value => 's.*y', :boost => 2.0}}}, + Query.new.regexp('name.first', 's.*y', :boost => 2.0, :fields => [:bar])) + end + + should "drop all the invalid flags" do + assert_equal({:regexp => {'name.first' => {:value => 's.*y', :flags => 'INTERSECTION|COMPLEMENT|EMPTY'}}}, + Query.new.regexp('name.first', 's.*y', :flags => [:intersection, :bar, :baz, :complement, :empty])) + end + end + end + end +end \ No newline at end of file