lib/neo4j/index/lucene_query.rb in neo4j-1.0.0.beta.18 vs lib/neo4j/index/lucene_query.rb in neo4j-1.0.0.beta.19
- old
+ new
@@ -43,76 +43,111 @@
@index = index
@query = query
@decl_props = decl_props
end
+ # Since we include the Ruby Enumerable mixin we need this method.
def each
hits.each { |n| yield n.wrapper }
end
+ # Close hits
+ #
+ # Closes the underlying search result. This method should be called whenever you've got what you wanted from the result and won't use it anymore.
+ # It's necessary to call it so that underlying indexes can dispose of allocated resources for this search result.
+ # You can however skip to call this method if you loop through the whole result, then close() will be called automatically.
+ # Even if you loop through the entire result and then call this method it will silently ignore any consequtive call (for convenience).
+ #
+ # This must be done according to the Neo4j Java Documentation:
def close
@hits.close if @hits
end
+ # True if there is no search hits.
def empty?
hits.size == 0
end
+ # returns the n'th search item
+ # Does simply loop all search items till the n'th is found.
+ #
def [](index)
each_with_index {|node,i| break node if index == i}
end
+ # Returns the number of search hits
def size
hits.size
end
- def hits
+ def hits #:nodoc:
@hits ||= perform_query
end
- def between(lower, upper)
+ # Performs a range query
+ # Notice that if you don't specify a type when declaring a property a String range query will be performed.
+ #
+ def between(lower, upper, lower_incusive=false, upper_inclusive=false)
raise "Expected a symbol. Syntax for range queries example: index(:weight).between(a,b)" unless Symbol === @query
raise "Can't only do range queries on Neo4j::NodeMixin, Neo4j::Model, Neo4j::RelationshipMixin" unless @decl_props
- type = @decl_props[@query] && @decl_props[@query][:type]
- raise "Missing type declaration of property #{@query}. E.g. property :#{@query}, :type => Float; index :#{@query}" unless type
- if type != String
- raise "find(#{@query}).between(#{lower}, #{upper}) to allowed since #{lower} is not a Float or Fixnum" if lower === Float or lower === Fixnum
- raise "find(#{@query}).between(#{lower}, #{upper}) to allowed since #{upper} is not a Float or Fixnum" if upper === Float or upper === Fixnum
- @query = org.apache.lucene.search.NumericRangeQuery.new_double_range(@query.to_s, lower, upper, false, false)
- else
- raise "find(#{@query}).between(#{lower}, #{upper}) to allowed since #{lower} is not a String" if lower === String
- raise "find(#{@query}).between(#{lower}, #{upper}) to allowed since #{upper} is not a String" if upper === String
- @query = org.apache.lucene.search.TermRangeQuery.new(@query.to_s, lower, upper, false, false)
- end
+ # check that we perform a range query on the same values as we have declared with the property :key, :type => ...
+ type = @decl_props[@query] && @decl_props[@query][:type]
+ raise "find(#{@query}).between(#{lower}, #{upper}): #{lower} not a #{type}" if type && !type === lower.class
+ raise "find(#{@query}).between(#{lower}, #{upper}): #{upper} not a #{type}" if type && !type === upper.class
+
+ # Make it possible to convert those values
+ lower = TypeConverters.convert(lower)
+ upper = TypeConverters.convert(upper)
+
+ @query = case lower
+ when Fixnum
+ org.apache.lucene.search.NumericRangeQuery.new_long_range(@query.to_s, lower, upper, lower_incusive, upper_inclusive)
+ when Float
+ org.apache.lucene.search.NumericRangeQuery.new_double_range(@query.to_s, lower, upper, lower_incusive, upper_inclusive)
+ else
+ org.apache.lucene.search.TermRangeQuery.new(@query.to_s, lower, upper, lower_incusive, upper_inclusive)
+ end
self
end
+ # Create a compound lucene query.
+ #
+ # ==== Parameters
+ # query2 :: the query that should be AND together
+ #
+ # ==== Example
+ #
+ # Person.find(:name=>'kalle').and(:age => 3)
+ #
def and(query2)
new_query = LuceneQuery.new(@index, @decl_props, query2)
new_query.left_and_query = self
new_query
end
+
+ # Sort descending the given fields.
def desc(*fields)
@order = fields.inject(@order || {}) { |memo, field| memo[field] = true; memo }
self
end
+ # Sort ascending the given fields.
def asc(*fields)
@order = fields.inject(@order || {}) { |memo, field| memo[field] = false; memo }
self
end
- def build_and_query(query)
+ def build_and_query(query) #:nodoc:
left_query = @left_and_query.build_query
and_query = org.apache.lucene.search.BooleanQuery.new
and_query.add(left_query, org.apache.lucene.search.BooleanClause::Occur::MUST)
and_query.add(query, org.apache.lucene.search.BooleanClause::Occur::MUST)
and_query
end
- def build_sort_query(query)
+ def build_sort_query(query) #:nodoc:
java_sort_fields = @order.keys.inject([]) do |memo, field|
decl_type = @decl_props && @decl_props[field] && @decl_props[field][:type]
type = case
when Float == decl_type
org.apache.lucene.search.SortField::DOUBLE
@@ -125,11 +160,11 @@
end
sort = org.apache.lucene.search.Sort.new(*java_sort_fields)
org.neo4j.index.impl.lucene.QueryContext.new(query).sort(sort)
end
- def build_hash_query(query)
+ def build_hash_query(query) #:nodoc:
and_query = org.apache.lucene.search.BooleanQuery.new
query.each_pair do |key, value|
raise "Only String values valid in find(hash) got :#{key} => #{value} which is not a String" if !value.is_a?(String) && @decl_props[key] && @decl_props[key][:type] != String
term = org.apache.lucene.index.Term.new(key.to_s, value.to_s)
@@ -137,18 +172,18 @@
and_query.add(term_query, org.apache.lucene.search.BooleanClause::Occur::MUST)
end
and_query
end
- def build_query
+ def build_query #:nodoc:
query = @query
query = build_hash_query(query) if Hash === query
query = build_and_query(query) if @left_and_query
query = build_sort_query(query) if @order
query
end
- def perform_query
+ def perform_query #:nodoc:
@index.query(build_query)
end
end
end
end