CloudSesame 0.1.5 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b7aad854d12632f7a254e4d4130381ecf2c1e468
4
- data.tar.gz: d150f9b6a91d47da8fd83df34b967c78507221bf
3
+ metadata.gz: d640359762a517c60a26d82969d821678bb14871
4
+ data.tar.gz: 7d9e1082e91951cd4d61061de81cba3416f8c93b
5
5
  SHA512:
6
- metadata.gz: 1a2374d616b59d412dcc228f51343ce56e0d9686ffc322f272a7ded656976ffeaab5492cd83547feec36619279bea6a97d094f66b8377692f3e509f89122ce2b
7
- data.tar.gz: 816abf070d875a9d1d2df1e54bd0b1aa23618d09c1bcbf0d4e067c6abb6170667c8889b649066bd5fbe3d1aa4be712ce5251bfc73562fdd9a0f5c4ccac1f2ceb
6
+ metadata.gz: 392b5a7c410506f2a4c0547853c31e1ce282063191251eb3fa0f30b64cf3aa503d41bdb13e52ebaec879fa9de7f8dce00a34f846d667d6e0ea334d9b8dc4b55c
7
+ data.tar.gz: 064717d64e27d0ae3f172b7ab0d0bd870dd40240b93d17b5e4ff6fb6f75b7dd9cd6c4b5e0d1352dc9934997ef1c460a0ffab50c5f4b65a85736f34a7493ea1a6
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- CloudSesame (0.1.4)
4
+ CloudSesame (0.1.6)
5
5
  aws-sdk (~> 2)
6
6
 
7
7
  GEM
data/README.md ADDED
@@ -0,0 +1,57 @@
1
+ #CloudSesame
2
+ Light and Flexible CloudSearch Query Interface
3
+
4
+ #Install
5
+ * In terminal
6
+ ```gem install CloudSesame```
7
+ * In Gemfile
8
+ ```gem 'CloudSesame```
9
+
10
+ #Setup
11
+
12
+ 2. Initalize the gem
13
+ * Inside the Rails `config/initializers` folder, create a file called `cloud_sesame.rb`
14
+ * In the file, enter in your AWS credentials
15
+
16
+ ```
17
+ require 'cloud_sesame'
18
+ CloudSesame::Domain::Client.configure do |config|
19
+ config.access_key = ENV['AWS_ACCESS_KEY_ID']
20
+ config.secret_key = ENV['AWS_SECRET_ACCESS_KEY']
21
+ end
22
+ ```
23
+
24
+ 3. Setup your searchable model
25
+
26
+ * `include CloudSesame`
27
+ * call `define_cloudsearch` to setup your CloudSearch config, default size (optional), fields, and scopes (optional).
28
+
29
+ ```
30
+ class Product
31
+ include CloudSesame
32
+
33
+ define_cloudsearch do
34
+ config.endpoint = ENV[AWS_ENDPOINT]
35
+ config.region = END[AWS_REGION]
36
+
37
+ default_size 100 #will default to 10 if not defined
38
+
39
+ field :description, query: true
40
+ field :name, query: { weight: 2 }
41
+ field :currency, facet: true
42
+ field :manufacturer, facet: { size: 50 }
43
+ field :price, facet: { buckets: %w([0, 25], [25, 50], [50, 100]), method: 'interval'}
44
+
45
+ scope :puma_shoes, -> { query("shoes").and { manufacturer "Puma" } }
46
+ scope :puma_shoes do
47
+ query("shoes").and { manufacturer "Puma" }
48
+ end
49
+
50
+ end
51
+ end
52
+ ```
53
+
54
+ 4. How to define search fields
55
+ * to add a field to query_options, set `query: true`
56
+ * to add a field to query_options with a weight, set `query: { weight: <any integer> }`
57
+ * to add a field to filter_query, set `facet : true`
data/cloud_sesame.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'CloudSesame'
3
- s.version = '0.1.5'
3
+ s.version = '0.1.6'
4
4
  s.date = '2016-01-14'
5
5
  s.summary = "AWS CloudSearch Query Interface"
6
6
  s.description = "AWS CloudSearch Query Interface"
data/lib/cloud_sesame.rb CHANGED
@@ -21,26 +21,29 @@ require 'cloud_sesame/query/dsl/page'
21
21
  require 'cloud_sesame/query/dsl/sort'
22
22
  require 'cloud_sesame/query/dsl/and'
23
23
  require 'cloud_sesame/query/dsl/or'
24
- require 'cloud_sesame/query/dsl/range'
25
24
  require 'cloud_sesame/query/dsl/literal'
26
- require 'cloud_sesame/query/dsl/literal_helper'
25
+ require 'cloud_sesame/query/dsl/value'
27
26
  require 'cloud_sesame/query/dsl/scope'
28
27
  require 'cloud_sesame/query/dsl/filter_query'
28
+ require 'cloud_sesame/query/dsl/boost'
29
+ require 'cloud_sesame/query/dsl/return'
29
30
 
30
31
  # Query Query Filter Query AST Tree
31
32
  # ===============================================
32
33
  require 'cloud_sesame/query/ast/multi_branch'
33
34
  require 'cloud_sesame/query/ast/single_branch'
34
- require 'cloud_sesame/query/ast/root'
35
- require 'cloud_sesame/query/ast/leaf'
36
35
  require 'cloud_sesame/query/ast/multi_expression_operator'
36
+ require 'cloud_sesame/query/ast/single_expression_operator'
37
37
  require 'cloud_sesame/query/ast/and'
38
38
  require 'cloud_sesame/query/ast/or'
39
- require 'cloud_sesame/query/ast/single_expression_operator'
40
39
  require 'cloud_sesame/query/ast/not'
41
40
  require 'cloud_sesame/query/ast/near'
41
+ require 'cloud_sesame/query/ast/phrase'
42
42
  require 'cloud_sesame/query/ast/prefix'
43
+ require 'cloud_sesame/query/ast/term'
43
44
  require 'cloud_sesame/query/ast/compound_array'
45
+ require 'cloud_sesame/query/ast/root'
46
+ require 'cloud_sesame/query/ast/leaf'
44
47
  require 'cloud_sesame/query/ast/literal'
45
48
  require 'cloud_sesame/query/ast/value'
46
49
  require 'cloud_sesame/query/ast/date_value'
@@ -58,6 +61,7 @@ require 'cloud_sesame/query/node/filter_query'
58
61
  require 'cloud_sesame/query/node/facet'
59
62
  require 'cloud_sesame/query/node/page'
60
63
  require 'cloud_sesame/query/node/sort'
64
+ require 'cloud_sesame/query/node/return'
61
65
 
62
66
  # Query Builder Interface
63
67
  # ===============================================
@@ -2,17 +2,13 @@ module CloudSesame
2
2
  module Domain
3
3
  class Base
4
4
  extend Forwardable
5
- include Query::DSL::Scope
5
+ include Query::Builder
6
6
 
7
7
  attr_accessor :definition
8
- attr_reader :searchable
8
+ attr_reader :searchable, :result
9
9
 
10
10
  def_delegator :client, :config
11
11
 
12
- def_delegators :builder, :query, :page, :size, :sort,
13
- :and, :or, :included?, :excluded?,
14
- :method_context, :method_return, :method_scope
15
-
16
12
  def initialize(searchable)
17
13
  @searchable = searchable
18
14
  end
@@ -21,17 +17,13 @@ module CloudSesame
21
17
  @client ||= Client.new
22
18
  end
23
19
 
24
- def builder
25
- @builder ||= CloudSesame::Query::Builder.new context, searchable
20
+ def context
21
+ @context ||= Context.new
26
22
  end
27
23
 
28
24
  # DEFAULT CONTEXT METHODS
29
25
  # =========================================
30
26
 
31
- def context
32
- @context ||= Context.new
33
- end
34
-
35
27
  def default_size(value)
36
28
  context[:page, true][:size] = value
37
29
  end
@@ -2,70 +2,65 @@ module CloudSesame
2
2
  module Query
3
3
  module AST
4
4
  class CompoundArray < Array
5
- # include Range
6
5
 
7
- attr_accessor :scope, :parent, :literal
8
- attr_reader :field
6
+ attr_reader :scope, :field
9
7
 
10
- def field=(field)
11
- self.parent = nil
8
+ def for_field(field)
9
+ parents.clear
12
10
  @field = field
13
11
  end
14
12
 
15
- def set_scope(scope)
16
- self.scope = scope
13
+ def parents
14
+ @parents ||= []
15
+ end
16
+
17
+ def scope_to(scope)
18
+ @scope = scope
17
19
  return self
18
20
  end
19
21
 
20
22
  # SINGLE BRANCH OPERATOR
21
23
  # =======================================
22
24
 
23
- # NOT
25
+ # NEAR
24
26
  # =======================================
25
- def not(*values)
26
- self.parent = AST::Not
27
- insert_and_return_children(values)
27
+ def near(*values)
28
+ parents[1] = AST::Near
29
+ insert_and_return_children values
28
30
  end
29
31
 
30
- alias_method :is_not, :not
32
+ alias_method :sloppy, :near
31
33
 
32
- # NEAR
34
+ # NOT
33
35
  # =======================================
34
- def near(*values)
35
- self.parent = AST::Near
36
- insert_and_return_children(values)
36
+ def not(*values)
37
+ parents[0] = AST::Not
38
+ insert_and_return_children values
37
39
  end
38
40
 
39
- alias_method :sloppy, :near
41
+ alias_method :is_not, :not
40
42
 
41
- # PREFIX LITERAL
43
+ # PREFIX
42
44
  # =======================================
43
45
  def prefix(*values)
44
- self.parent = AST::Prefix
45
- insert_and_return_children(values)
46
+ parents[1] = AST::Prefix
47
+ insert_and_return_children values
46
48
  end
47
49
 
48
50
  alias_method :start_with, :prefix
49
51
  alias_method :begin_with, :prefix
50
52
 
51
- # RANGE LITERAL
52
- # =======================================
53
- # def range
54
- # self.literal = AST::PrefixLiteral
55
- # insert_and_return_children(values)
56
- # return self
57
- # end
58
-
59
- # alias_method :start_with, :prefix
60
-
61
53
  def insert_and_return_children(values = [])
62
54
  values.each do |value|
63
- if parent
64
- self << (node = parent.new scope.context)
65
- node.child = AST::Literal.new(field, value, options)
66
- else
67
- self << AST::Literal.new(field, value, options)
55
+ value.child.field = field if value.kind_of?(AST::SingleExpressionOperator)
56
+ child = value.kind_of?(AST::SingleExpressionOperator) || value.kind_of?(AST::Literal) ? value : AST::Literal.new(field, value, options)
57
+
58
+ current_scope = self
59
+ parents.compact.each do |parent|
60
+ current_scope << (node = parent.new scope.context)
61
+ current_scope = node
68
62
  end
63
+ current_scope << child
69
64
  end
70
65
  return self
71
66
  end
@@ -3,16 +3,8 @@ module CloudSesame
3
3
  module AST
4
4
  class DateValue < Value
5
5
 
6
- def initialize(data)
7
- @data = data
8
- end
9
-
10
6
  def compile
11
- strip escape @data.strftime('%FT%TZ')
12
- end
13
-
14
- def to_s
15
- compile
7
+ strip escape data.strftime '%FT%TZ'
16
8
  end
17
9
 
18
10
  end
@@ -4,41 +4,41 @@ module CloudSesame
4
4
  class Literal < SingleBranch
5
5
 
6
6
  attr_accessor :field
7
- attr_reader :value, :options
7
+ attr_reader :options, :value
8
8
 
9
- def initialize(field, value, options = {})
10
- self.field = field
11
- self.value = value
12
-
13
- @options = options
14
- (options[:included] ||= []) << value
15
- end
16
-
17
- def detailed
18
- options[:detailed] = true
19
- return self
9
+ def initialize(field = nil, value = nil, options = {})
10
+ @field = field
11
+ @value = to_value value
12
+ ((@options = options || {})[:included] ||= []) << @value
20
13
  end
21
14
 
22
- def value=(value)
23
- @value = value.kind_of?(Value) ? value : Value.new(value)
15
+ def as_field
16
+ options[:as] || field
24
17
  end
25
18
 
26
19
  def compile
27
- options[:detailed] ? long_format : short_format
20
+ options[:detailed] ? detailed_format : standard_format
28
21
  end
29
22
 
30
- def as_field
31
- options[:as] || field
23
+ def detailed
24
+ options[:detailed] = true
25
+ return self
32
26
  end
33
27
 
34
28
  private
35
29
 
36
- def short_format
37
- "#{ as_field }:#{ value.compile }"
30
+ def to_value(value)
31
+ return value if value.kind_of? Value
32
+ return RangeValue.new value if value.kind_of? Range
33
+ return DateValue.new(value) if value.kind_of?(Date) || value.kind_of?(Time)
34
+ Value.new value
38
35
  end
39
36
 
37
+ def standard_format
38
+ "#{ as_field }:#{ value.compile }"
39
+ end
40
40
 
41
- def long_format
41
+ def detailed_format
42
42
  "field=#{ escape as_field } #{ value.compile }"
43
43
  end
44
44
 
@@ -14,7 +14,7 @@ module CloudSesame
14
14
  end
15
15
 
16
16
  def children
17
- @children ||= CompoundArray.new.set_scope self
17
+ @children ||= CompoundArray.new.scope_to self
18
18
  end
19
19
 
20
20
  def compile_children
@@ -2,20 +2,18 @@ module CloudSesame
2
2
  module Query
3
3
  module AST
4
4
  class MultiExpressionOperator < MultiBranch
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 } #{ compile_children })" unless children.empty?
16
+ "(#{ self.class.symbol }#{ compile_boost } #{ compile_children })" unless children.empty?
19
17
  end
20
18
 
21
19
  end
@@ -5,10 +5,19 @@ module CloudSesame
5
5
  self.symbol = :near
6
6
 
7
7
  def compile
8
- child.detailed
9
- super
8
+ child.detailed if child.kind_of?(Literal)
9
+ "(#{ self.class.symbol }#{ compile_boost }#{ compile_distance } #{ child.compile })" if child
10
10
  end
11
11
 
12
+ def distance(value)
13
+ @distance = value.to_i
14
+ return self
15
+ end
16
+
17
+ def compile_distance
18
+ " distance=#{ @distance }" if @distance
19
+ end
20
+
12
21
  end
13
22
  end
14
23
  end
@@ -0,0 +1,14 @@
1
+ module CloudSesame
2
+ module Query
3
+ module AST
4
+ class Phrase < SingleExpressionOperator
5
+ self.symbol = :phrase
6
+
7
+ def compile
8
+ child.detailed if child.kind_of?(Literal)
9
+ super
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -5,10 +5,9 @@ module CloudSesame
5
5
  self.symbol = :prefix
6
6
 
7
7
  def compile
8
- child.detailed
8
+ child.detailed if child.kind_of?(Literal)
9
9
  super
10
10
  end
11
-
12
11
  end
13
12
  end
14
13
  end
@@ -3,73 +3,48 @@ module CloudSesame
3
3
  module AST
4
4
  class RangeValue < Value
5
5
 
6
- attr_accessor :lower_bound_included,
7
- :upper_bound_included
8
-
9
- def initialize
10
- @data = [nil, nil]
6
+ def initialize(range = nil)
7
+ @data = range ? [true, to_value(range.begin), to_value(range.end), !range.exclude_end?] : [false, nil, nil, false]
11
8
  end
12
9
 
13
10
  def compile
14
- strip "#{ lower_bound }#{ lower.compile if lower },#{ upper.compile if upper }#{ upper_bound }"
15
- end
16
-
17
- def to_s
18
- compile
11
+ "#{ lb }#{ data[1].to_s },#{ data[2].to_s }#{ ub }"
19
12
  end
20
13
 
21
14
  def gt(value)
22
- self.lower = value
23
- self.lower_bound_included = false
15
+ data[0], data[1] = false, to_value(value)
24
16
  return self
25
17
  end
26
18
 
27
19
  def gte(value)
28
- self.lower = value
29
- self.lower_bound_included = true
20
+ data[0], data[1] = true, to_value(value)
30
21
  return self
31
22
  end
32
23
 
33
24
  def lt(value)
34
- self.upper = value
35
- self.upper_bound_included = false
25
+ data[2], data[3] = to_value(value), false
36
26
  return self
37
27
  end
38
28
 
39
29
  def lte(value)
40
- self.upper = value
41
- self.upper_bound_included = true
30
+ data[2], data[3] = to_value(value), true
42
31
  return self
43
32
  end
44
33
 
45
- def lower
46
- data[0]
47
- end
48
-
49
- def lower=(value)
50
- data[0] = to_value(value)
51
- end
52
-
53
- def upper
54
- data[1]
55
- end
56
-
57
- def upper=(value)
58
- data[1] = to_value(value)
59
- end
34
+ private
60
35
 
61
- def lower_bound
62
- lower && lower_bound_included ? '[' : '{'
36
+ def to_value(value)
37
+ return value if value.kind_of? Value
38
+ return DateValue.new(value) if value.kind_of?(Date) || value.kind_of?(Time)
39
+ Value.new value
63
40
  end
64
41
 
65
- def upper_bound
66
- upper && upper_bound_included ? ']' : '}'
42
+ def lb
43
+ data[1] && data[0] ? '[' : '{'
67
44
  end
68
45
 
69
- private
70
-
71
- def to_value(value)
72
- value.kind_of?(Value) ? value : Value.new(value)
46
+ def ub
47
+ data[2] && data[3] ? ']' : '}'
73
48
  end
74
49
 
75
50
  end