CloudSesame 0.1.5 → 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/README.md +57 -0
  4. data/cloud_sesame.gemspec +1 -1
  5. data/lib/cloud_sesame.rb +9 -5
  6. data/lib/cloud_sesame/domain/base.rb +4 -12
  7. data/lib/cloud_sesame/query/ast/compound_array.rb +30 -35
  8. data/lib/cloud_sesame/query/ast/date_value.rb +1 -9
  9. data/lib/cloud_sesame/query/ast/literal.rb +20 -20
  10. data/lib/cloud_sesame/query/ast/multi_branch.rb +1 -1
  11. data/lib/cloud_sesame/query/ast/multi_expression_operator.rb +2 -4
  12. data/lib/cloud_sesame/query/ast/near.rb +11 -2
  13. data/lib/cloud_sesame/query/ast/phrase.rb +14 -0
  14. data/lib/cloud_sesame/query/ast/prefix.rb +1 -2
  15. data/lib/cloud_sesame/query/ast/range_value.rb +16 -41
  16. data/lib/cloud_sesame/query/ast/root.rb +3 -13
  17. data/lib/cloud_sesame/query/ast/single_branch.rb +5 -2
  18. data/lib/cloud_sesame/query/ast/single_expression_operator.rb +2 -4
  19. data/lib/cloud_sesame/query/ast/term.rb +14 -0
  20. data/lib/cloud_sesame/query/ast/value.rb +10 -2
  21. data/lib/cloud_sesame/query/builder.rb +30 -5
  22. data/lib/cloud_sesame/query/dsl/boost.rb +20 -0
  23. data/lib/cloud_sesame/query/dsl/filter_query.rb +11 -20
  24. data/lib/cloud_sesame/query/dsl/literal.rb +48 -8
  25. data/lib/cloud_sesame/query/dsl/page.rb +4 -0
  26. data/lib/cloud_sesame/query/dsl/return.rb +21 -0
  27. data/lib/cloud_sesame/query/dsl/value.rb +28 -0
  28. data/lib/cloud_sesame/query/node/request.rb +6 -1
  29. data/lib/cloud_sesame/query/node/return.rb +21 -0
  30. data/spec/cloud_sesame/query/ast/multi_branch_spec.rb +1 -1
  31. data/spec/cloud_sesame/query/ast/multi_expression_operator_spec.rb +0 -4
  32. data/spec/cloud_sesame/query/dsl/filter_query_spec.rb +6 -56
  33. data/spec/cloud_sesame/query/node/request_spec.rb +2 -2
  34. data/spec/cloud_sesame_spec.rb +22 -7
  35. metadata +8 -3
  36. data/lib/cloud_sesame/query/dsl/literal_helper.rb +0 -17
  37. data/lib/cloud_sesame/query/dsl/range.rb +0 -41
@@ -1,21 +1,11 @@
1
1
  module CloudSesame
2
2
  module Query
3
3
  module AST
4
- class Root < MultiBranch
4
+ class Root < And
5
+ self.symbol = :and
5
6
 
6
7
  def compile
7
- if children.size > 1
8
- join_by_default_operator.compile
9
- else
10
- compile_children
11
- end
12
- end
13
-
14
- private
15
-
16
- def join_by_default_operator
17
- (default = And.new context).children.concat children
18
- default
8
+ children.size > 1 ? super : compile_children
19
9
  end
20
10
 
21
11
  end
@@ -2,7 +2,6 @@ module CloudSesame
2
2
  module Query
3
3
  module AST
4
4
  class SingleBranch
5
-
6
5
  attr_accessor :child
7
6
  attr_reader :context
8
7
 
@@ -13,11 +12,15 @@ module CloudSesame
13
12
 
14
13
  def child=(object)
15
14
  if object.kind_of? Literal
16
- (object.options[:excluded] ||= []) << object.options[:included].delete(object.value.data)
15
+ (object.options[:excluded] ||= []) << object.options[:included].delete(object.value)
17
16
  end
18
17
  @child = object
19
18
  end
20
19
 
20
+ def <<(object)
21
+ self.child= object
22
+ end
23
+
21
24
  end
22
25
  end
23
26
  end
@@ -2,20 +2,18 @@ module CloudSesame
2
2
  module Query
3
3
  module AST
4
4
  class SingleExpressionOperator < SingleBranch
5
+ include DSL::Boost
5
6
 
6
- # Operator Symbol Writer
7
7
  def self.symbol=(symbol)
8
8
  @symbol = symbol
9
9
  end
10
10
 
11
- # Operator Symbol Getter
12
11
  def self.symbol
13
12
  @symbol
14
13
  end
15
14
 
16
15
  def compile
17
- raise Error::MissingOperatorSymbol if self.class.symbol.nil?
18
- "(#{ self.class.symbol } #{ child.compile })" if child
16
+ "(#{ self.class.symbol }#{ compile_boost } #{ child.compile })" if child
19
17
  end
20
18
 
21
19
  end
@@ -0,0 +1,14 @@
1
+ module CloudSesame
2
+ module Query
3
+ module AST
4
+ class Term < SingleExpressionOperator
5
+ self.symbol = :term
6
+
7
+ def compile
8
+ child.detailed if child.kind_of?(Literal)
9
+ super
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -3,14 +3,22 @@ module CloudSesame
3
3
  module AST
4
4
  class Value < Leaf
5
5
 
6
- attr_accessor :data
6
+ attr_reader :data
7
7
 
8
8
  def initialize(data)
9
9
  @data = data
10
10
  end
11
11
 
12
12
  def compile
13
- format(data)
13
+ format data
14
+ end
15
+
16
+ def ==(value)
17
+ data == value || compile == value
18
+ end
19
+
20
+ def to_s
21
+ compile
14
22
  end
15
23
 
16
24
  private
@@ -1,13 +1,14 @@
1
1
  module CloudSesame
2
2
  module Query
3
- class Builder
3
+ module Builder
4
4
  include DSL::Base
5
5
  include DSL::FilterQuery
6
6
  include DSL::Page
7
7
  include DSL::Query
8
8
  include DSL::Sort
9
+ include DSL::Return
9
10
 
10
- attr_reader :context, :searchable, :result
11
+ attr_reader :result
11
12
 
12
13
  def initialize(default_context, searchable)
13
14
  @context = default_context
@@ -18,26 +19,50 @@ module CloudSesame
18
19
  @request ||= (clear_result; Node::Request.new context.dup)
19
20
  end
20
21
 
22
+ def response
23
+ @response ||= search
24
+ end
25
+
21
26
  def clear_request
22
27
  @request = nil
23
28
  end
24
29
 
25
30
  def clear_result
26
- @result = nil
31
+ @response = nil
32
+ end
33
+
34
+ def compile
35
+ request.compile
27
36
  end
28
37
 
29
38
  def inspect
30
- "#<CloudSesame::Query::Builder:#{ object_id } #{ request.compile }>"
39
+ "#<#{ self.class }:#{ object_id } #{ compile }>"
31
40
  end
32
41
 
33
42
  # ENDING METHODS
34
43
  # =========================================
35
44
 
45
+ def found
46
+ response.hits.found
47
+ end
48
+
49
+ def results
50
+ response.hits.hit
51
+ end
52
+
53
+ def each(&block)
54
+ results.each &block
55
+ end
56
+
57
+ def map(&block)
58
+ results.map &block
59
+ end
60
+
36
61
  def search
37
62
  compiled = request.compile
38
63
  raise Error::MissingQuery.new("Query or FilterQuery can not be empty!") if !compiled[:query] || compiled[:query].empty?
39
64
  clear_request
40
- @result = searchable.cloudsearch.client.search compiled
65
+ @response = client.search compiled
41
66
  end
42
67
 
43
68
  private
@@ -0,0 +1,20 @@
1
+ module CloudSesame
2
+ module Query
3
+ module DSL
4
+ module Boost
5
+
6
+ def compile_boost
7
+ " boost=#{ @boost }" if @boost
8
+ end
9
+
10
+ def boost(value)
11
+ @boost = value.to_i
12
+ return self
13
+ end
14
+
15
+ alias_method :weight, :boost
16
+
17
+ end
18
+ end
19
+ end
20
+ end
@@ -2,43 +2,34 @@ module CloudSesame
2
2
  module Query
3
3
  module DSL
4
4
  module FilterQuery
5
- include Scope
6
5
  include And
7
- include Or
8
6
  include Literal
9
- include LiteralHelper
7
+ include Or
8
+ include Scope
9
+ include Value
10
10
 
11
- # { fields: { tags: { excluded: [100] } } }
12
11
  def included?(field, value = nil)
13
12
  (field_options = method_scope.context[:fields][field]) && (
14
- (value && field_includes?(field_options, value)) ||
15
- (!value && field_included_is_not_empty?(field_options))
13
+ (value && field_options_is(:included, field_options, value)) ||
14
+ (!value && field_options_not_empty_in(:included, field_options))
16
15
  )
17
16
  end
18
17
 
19
18
  def excluded?(field, value = nil)
20
19
  (field_options = method_scope.context[:fields][field]) && (
21
- (value && field_excludes?(field_options, value)) ||
22
- (!value && field_excluded_is_not_empty?(field_options))
20
+ (value && field_options_is(:excluded, field_options, value)) ||
21
+ (!value && field_options_not_empty_in(:excluded, field_options))
23
22
  )
24
23
  end
25
24
 
26
25
  private
27
26
 
28
- def field_includes?(field_options, value)
29
- field_options[:included] && field_options[:included].include?(value)
30
- end
31
-
32
- def field_included_is_not_empty?(field_options)
33
- field_options[:included] && !field_options[:included].empty?
34
- end
35
-
36
- def field_excludes?(field_options, value)
37
- field_options[:excluded] && field_options[:excluded].include?(value)
27
+ def field_options_is(type, field_options, value)
28
+ (values = field_options[type]) && values.include?(value)
38
29
  end
39
30
 
40
- def field_excluded_is_not_empty?(field_options)
41
- field_options[:excluded] && !field_options[:excluded].empty?
31
+ def field_options_not_empty_in(type, field_options)
32
+ field_options[type] && !field_options[type].empty?
42
33
  end
43
34
 
44
35
 
@@ -3,12 +3,45 @@ module CloudSesame
3
3
  module DSL
4
4
  module Literal
5
5
 
6
- # CLAUSE: LITERAL
7
- # =========================================
8
- def literal(field, value, options = {})
9
- node = AST::Literal.new(field, value, options)
10
- method_scope.children << node
11
- node
6
+ # LITERAL: creates a single LITERAL node
7
+ # =======================================
8
+ def literal(value)
9
+ field = method_scope.children.field
10
+ AST::Literal.new field, value, fields[field]
11
+ end
12
+
13
+ alias_method :l, :literal
14
+ alias_method :field, :literal
15
+
16
+ # NEAR: creates a single NEAR node
17
+ # =======================================
18
+ def near(value)
19
+ create_literal_with_operator AST::Near, value
20
+ end
21
+
22
+ alias_method :n, :near
23
+ alias_method :sloppy, :near
24
+
25
+ # PREFIX: creates a single PREFIX node
26
+ # =======================================
27
+ def prefix(value)
28
+ create_literal_with_operator AST::Prefix, value
29
+ end
30
+
31
+ alias_method :p, :prefix
32
+ alias_method :start_with, :prefix
33
+ alias_method :begin_with, :prefix
34
+
35
+ # PHRASE: creates a single PHRASE node
36
+ # =======================================
37
+ def phrase(value)
38
+ create_literal_with_operator AST::Phrase, value
39
+ end
40
+
41
+ # TERM: creates a single TERM node
42
+ # =======================================
43
+ def term(value)
44
+ create_literal_with_operator AST::Term, value
12
45
  end
13
46
 
14
47
  private
@@ -17,10 +50,17 @@ module CloudSesame
17
50
  method_context[:fields]
18
51
  end
19
52
 
53
+ def create_literal_with_operator(klass, value)
54
+ field = method_scope.children.field
55
+ literal = AST::Literal.new field, value, fields[field]
56
+ (node = klass.new method_context) << literal
57
+ node
58
+ end
59
+
20
60
  def method_missing(field, *values, &block)
21
61
  if fields && (options = fields[field])
22
- method_scope.children.field = field
23
- method_scope.children.insert_and_return_children(values)
62
+ method_scope.children.for_field field
63
+ method_scope.children.insert_and_return_children values
24
64
  else
25
65
  super
26
66
  end
@@ -3,6 +3,8 @@ module CloudSesame
3
3
  module DSL
4
4
  module Page
5
5
 
6
+ # CLAUSE: PAGE and SIZE
7
+ # =========================================
6
8
  def page(input = nil)
7
9
  if input
8
10
  request.page.page = input.to_i
@@ -21,6 +23,8 @@ module CloudSesame
21
23
  end
22
24
  end
23
25
 
26
+ alias_method :limit, :size
27
+
24
28
  end
25
29
  end
26
30
  end
@@ -0,0 +1,21 @@
1
+ module CloudSesame
2
+ module Query
3
+ module DSL
4
+ module Return
5
+
6
+ def all_fields
7
+ request.return_field.value = :all_fields
8
+ end
9
+
10
+ def no_fields
11
+ request.return_field.value = :no_fields
12
+ end
13
+
14
+ def score
15
+ request.return_field.value = :score
16
+ end
17
+
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,28 @@
1
+ module CloudSesame
2
+ module Query
3
+ module DSL
4
+ module Value
5
+
6
+ # VALUE DSL
7
+ # =======================================
8
+
9
+ # DATE
10
+ # =======================================
11
+ def date(date)
12
+ AST::DateValue.new date
13
+ end
14
+
15
+ alias_method :d, :date
16
+
17
+ # RANGE
18
+ # =======================================
19
+ def range(range = nil)
20
+ AST::RangeValue.new range
21
+ end
22
+
23
+ alias_method :r, :range
24
+
25
+ end
26
+ end
27
+ end
28
+ end
@@ -34,6 +34,10 @@ module CloudSesame
34
34
  @sort ||= Sort.new(context[:sort, true])
35
35
  end
36
36
 
37
+ def return_field
38
+ @return ||= Return.new(context[:return, true])
39
+ end
40
+
37
41
  # EVALUATION
38
42
  # =========================================
39
43
 
@@ -44,7 +48,8 @@ module CloudSesame
44
48
  query_parser,
45
49
  filter_query,
46
50
  page,
47
- sort
51
+ sort,
52
+ return_field
48
53
  ].each_with_object({}) do |node, compiled|
49
54
  compiled.merge!(node.compile || {})
50
55
  end
@@ -0,0 +1,21 @@
1
+ module CloudSesame
2
+ module Query
3
+ module Node
4
+ class Return < Abstract
5
+
6
+ attr_accessor :value
7
+
8
+ def compile
9
+ { return: format(value) } if value
10
+ end
11
+
12
+ private
13
+
14
+ def format(value)
15
+ value.to_s.gsub(/^_?/, '_')
16
+ end
17
+
18
+ end
19
+ end
20
+ end
21
+ end