CloudSesame 0.6.8 → 0.7.0

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 (101) hide show
  1. checksums.yaml +4 -4
  2. data/.editorconfig +12 -0
  3. data/.gitignore +1 -1
  4. data/Gemfile.lock +13 -13
  5. data/Guardfile +1 -0
  6. data/cloud_sesame.gemspec +2 -2
  7. data/coverage/.last_run.json +1 -1
  8. data/coverage/.resultset.json +679 -591
  9. data/lib/cloud_sesame/config/credential.rb +6 -6
  10. data/lib/cloud_sesame/context.rb +0 -5
  11. data/lib/cloud_sesame/domain/base.rb +147 -128
  12. data/lib/cloud_sesame/domain/client.rb +25 -25
  13. data/lib/cloud_sesame/domain/client_module/caching/base.rb +19 -23
  14. data/lib/cloud_sesame/domain/client_module/caching/no_cache.rb +11 -11
  15. data/lib/cloud_sesame/domain/client_module/caching/rails_cache.rb +32 -28
  16. data/lib/cloud_sesame/domain/client_module/caching.rb +19 -28
  17. data/lib/cloud_sesame/domain/client_module/retry.rb +6 -6
  18. data/lib/cloud_sesame/domain/config.rb +6 -6
  19. data/lib/cloud_sesame/query/ast/abstract/multi_expression_operator.rb +37 -0
  20. data/lib/cloud_sesame/query/ast/abstract/operator.rb +27 -0
  21. data/lib/cloud_sesame/query/ast/abstract/single_expression_operator.rb +39 -0
  22. data/lib/cloud_sesame/query/ast/abstract/value.rb +88 -0
  23. data/lib/cloud_sesame/query/ast/and.rb +1 -1
  24. data/lib/cloud_sesame/query/ast/date_value.rb +19 -3
  25. data/lib/cloud_sesame/query/ast/literal.rb +13 -28
  26. data/lib/cloud_sesame/query/ast/near.rb +4 -4
  27. data/lib/cloud_sesame/query/ast/not.rb +6 -7
  28. data/lib/cloud_sesame/query/ast/numeric_value.rb +20 -12
  29. data/lib/cloud_sesame/query/ast/or.rb +1 -1
  30. data/lib/cloud_sesame/query/ast/phrase.rb +1 -1
  31. data/lib/cloud_sesame/query/ast/prefix.rb +1 -1
  32. data/lib/cloud_sesame/query/ast/range_value.rb +40 -39
  33. data/lib/cloud_sesame/query/ast/root.rb +2 -6
  34. data/lib/cloud_sesame/query/ast/string_value.rb +26 -0
  35. data/lib/cloud_sesame/query/ast/term.rb +1 -1
  36. data/lib/cloud_sesame/query/ast/value.rb +25 -54
  37. data/lib/cloud_sesame/query/builder.rb +83 -54
  38. data/lib/cloud_sesame/query/domain/block.rb +3 -1
  39. data/lib/cloud_sesame/query/dsl/applied_filter_query.rb +14 -23
  40. data/lib/cloud_sesame/query/dsl/field_accessors.rb +25 -22
  41. data/lib/cloud_sesame/query/dsl/field_array_methods.rb +1 -1
  42. data/lib/cloud_sesame/query/dsl/inspect_method.rb +31 -0
  43. data/lib/cloud_sesame/query/dsl/sort_methods.rb +5 -4
  44. data/lib/cloud_sesame/query/node/abstract.rb +1 -2
  45. data/lib/cloud_sesame/query/node/facet.rb +1 -5
  46. data/lib/cloud_sesame/query/node/filter_query.rb +15 -2
  47. data/lib/cloud_sesame/query/node/fuzziness.rb +4 -3
  48. data/lib/cloud_sesame/query/node/page.rb +2 -2
  49. data/lib/cloud_sesame/query/node/query.rb +4 -17
  50. data/lib/cloud_sesame/query/node/query_options.rb +6 -16
  51. data/lib/cloud_sesame/query/node/query_options_field.rb +3 -1
  52. data/lib/cloud_sesame/query/node/query_parser.rb +8 -10
  53. data/lib/cloud_sesame/query/node/request.rb +57 -31
  54. data/lib/cloud_sesame/query/node/sort.rb +25 -11
  55. data/lib/cloud_sesame.rb +15 -12
  56. data/lib/{abstract_object.rb → services/abstract_object.rb} +0 -0
  57. data/lib/services/class_specific.rb +44 -0
  58. data/lib/services/lazy_object.rb +19 -0
  59. data/spec/cloud_sesame/domain/base_spec.rb +26 -11
  60. data/spec/cloud_sesame/domain/client_module/caching/base_spec.rb +2 -1
  61. data/spec/cloud_sesame/domain/client_module/caching/no_cache_spec.rb +2 -3
  62. data/spec/cloud_sesame/domain/client_module/caching/rails_cache_spec.rb +6 -6
  63. data/spec/cloud_sesame/domain/client_module/caching_spec.rb +33 -32
  64. data/spec/cloud_sesame/query/ast/abstract/multi_expression_operator_spec.rb +67 -0
  65. data/spec/cloud_sesame/query/ast/abstract/operator_spec.rb +29 -0
  66. data/spec/cloud_sesame/query/ast/abstract/single_expression_operator_spec.rb +70 -0
  67. data/spec/cloud_sesame/query/ast/abstract/value_spec.rb +118 -0
  68. data/spec/cloud_sesame/query/ast/and_spec.rb +1 -1
  69. data/spec/cloud_sesame/query/ast/or_spec.rb +1 -1
  70. data/spec/cloud_sesame/query/ast/range_value_spec.rb +5 -11
  71. data/spec/cloud_sesame/query/builder_spec.rb +10 -4
  72. data/spec/cloud_sesame/query/domain/block_spec.rb +15 -8
  73. data/spec/cloud_sesame/query/dsl/{block_methods_spec.rb → block_styled_operators_spec.rb} +0 -0
  74. data/spec/cloud_sesame/query/dsl/field_accessors_spec.rb +88 -50
  75. data/spec/cloud_sesame/query/dsl/field_array_methods_spec.rb +0 -2
  76. data/spec/cloud_sesame/query/node/facet_spec.rb +1 -15
  77. data/spec/cloud_sesame/query/node/filter_query_spec.rb +16 -2
  78. data/spec/cloud_sesame/query/node/page_spec.rb +3 -2
  79. data/spec/cloud_sesame/query/node/query_options_spec.rb +1 -1
  80. data/spec/cloud_sesame/query/node/query_parser_spec.rb +1 -7
  81. data/spec/cloud_sesame/query/node/query_spec.rb +10 -28
  82. data/spec/cloud_sesame/query/node/sort_spec.rb +19 -28
  83. data/spec/cloud_sesame_spec.rb +2 -156
  84. data/spec/helpers/benchmark_helper.rb +12 -0
  85. data/spec/integration/filter_query_spec.rb +0 -0
  86. data/spec/profiling_spec.rb +155 -0
  87. data/spec/{abstract_object_spec.rb → services/abstract_object_spec.rb} +0 -0
  88. data/spec/services/class_specific_spec.rb +135 -0
  89. data/spec/spec_helper.rb +3 -0
  90. metadata +32 -22
  91. data/lib/active_support/core_ext/object/deep_dup.rb +0 -53
  92. data/lib/active_support/core_ext/object/duplicable.rb +0 -98
  93. data/lib/cloud_sesame/query/ast/multi_expression_operator.rb +0 -35
  94. data/lib/cloud_sesame/query/ast/operator.rb +0 -25
  95. data/lib/cloud_sesame/query/ast/single_expression_operator.rb +0 -35
  96. data/lib/cloud_sesame/query/scope.rb +0 -21
  97. data/profiler.rb +0 -91
  98. data/spec/cloud_sesame/query/ast/multi_expression_operator_spec.rb +0 -76
  99. data/spec/cloud_sesame/query/ast/operator_spec.rb +0 -29
  100. data/spec/cloud_sesame/query/ast/single_expression_operator_spec.rb +0 -78
  101. data/spec/context_spec.rb +0 -17
@@ -1,56 +1,85 @@
1
1
  module CloudSesame
2
- module Query
3
- class Builder
4
- include DSL::QueryMethods
5
- include DSL::ResponseMethods
6
- include DSL::BlockStyledOperators
7
- include DSL::FieldAccessors
8
- include DSL::ScopeAccessors
9
- include DSL::AppliedFilterQuery
10
- include DSL::PageMethods
11
- include DSL::SortMethods
12
- include DSL::ReturnMethods
13
-
14
- attr_reader :context, :searchable
15
-
16
- def initialize(context, searchable)
17
- @context = Context.new.duplicate context
18
- @searchable = searchable
19
- end
20
-
21
- def request
22
- @request ||= Node::Request.new context
23
- end
24
-
25
- def compile
26
- request.compile
27
- end
28
-
29
- def inspect
30
- "#<#{ self.class }:#{ object_id } #{ compile }>"
31
- end
32
-
33
- private
34
-
35
- def _block_domain(block)
36
- if block
37
- caller = block.binding.eval("self")
38
- Domain::Block.new caller, _context
39
- end
40
- end
41
-
42
- def _scope
43
- request.filter_query.root
44
- end
45
-
46
- def _context
47
- _scope.context
48
- end
49
-
50
- def _return
51
- self
52
- end
53
-
54
- end
55
- end
2
+ module Query
3
+ class Builder
4
+ extend ClassSpecific
5
+ include DSL::AppliedFilterQuery
6
+ include DSL::BlockStyledOperators
7
+ include DSL::InspectMethod
8
+ include DSL::PageMethods
9
+ include DSL::QueryMethods
10
+ include DSL::ResponseMethods
11
+ include DSL::ReturnMethods
12
+ include DSL::ScopeAccessors
13
+ include DSL::SortMethods
14
+
15
+ # ClassSpecific construct class callback
16
+ #
17
+ # after construct searchable specific builder,
18
+ # construct searchable specific DSL::FieldAccessors,
19
+ # and Domain::Block and include the new field accessors
20
+ # in both builder and domain block
21
+ # ===================================================
22
+ after_construct do |searchable|
23
+ @field_accessor = DSL::FieldAccessors.construct_module(searchable)
24
+ @block_domain = Domain::Block.construct_class(searchable, callback_args: [field_accessor])
25
+ @request = Node::Request.construct_class(searchable)
26
+
27
+ include field_accessor
28
+ end
29
+
30
+ # Domain::Block getter
31
+ def self.block_domain
32
+ @block_domain ||= Domain::Block
33
+ end
34
+
35
+ # Node::Request getter
36
+ def self.request
37
+ @request ||= Node::Request
38
+ end
39
+
40
+ # DSL::FieldAccessors getter
41
+ def self.field_accessor
42
+ @field_accessor ||= DSL::FieldAccessors
43
+ end
44
+
45
+ # ===================================================
46
+
47
+ attr_reader :context, :searchable
48
+
49
+ def initialize(context, searchable)
50
+ @context = context
51
+ @searchable = searchable
52
+ end
53
+
54
+ def request
55
+ @request ||= self.class.request.new context
56
+ end
57
+
58
+ def compile
59
+ request.compile
60
+ end
61
+
62
+ private
63
+
64
+ def _block_domain(block)
65
+ if block
66
+ caller = block.binding.eval("self")
67
+ self.class.block_domain.new caller, _context
68
+ end
69
+ end
70
+
71
+ def _scope
72
+ request.filter_query.root
73
+ end
74
+
75
+ def _context
76
+ _scope.context
77
+ end
78
+
79
+ def _return
80
+ self
81
+ end
82
+
83
+ end
84
+ end
56
85
  end
@@ -2,14 +2,16 @@ module CloudSesame
2
2
  module Query
3
3
  module Domain
4
4
  class Block
5
+ extend ClassSpecific
5
6
  include DSL::AppliedFilterQuery
6
7
  include DSL::BlockStyledOperators
7
- include DSL::FieldAccessors
8
8
  include DSL::Operators
9
9
  include DSL::RangeHelper
10
10
  include DSL::ScopeAccessors
11
11
  include DSL::BindCaller
12
12
 
13
+ after_construct { |_, field_accessor| include field_accessor }
14
+
13
15
  attr_reader :_caller, :_context, :_scopes
14
16
 
15
17
  def initialize(_caller, _context)
@@ -4,42 +4,33 @@ module CloudSesame
4
4
  module AppliedFilterQuery
5
5
 
6
6
  def included?(field, value = nil)
7
- return false unless (options = field_options_for(field)) && (applied = options[:applied])
8
- if value
9
- (index = applied.keys.index(value)) &&
10
- (applied.values[index] != false)
11
- else
12
- applied.values.any?
13
- end
7
+ applied?(field, value, true)
14
8
  end
15
9
 
16
10
  def excluded?(field, value = nil)
17
- return false unless (options = field_options_for(field)) && (applied = options[:applied])
11
+ applied?(field, value, false)
12
+ end
13
+
14
+ def applied?(field, value, included = nil)
15
+ field = field.to_sym
16
+ applied = applied_filters(included)
18
17
  if value
19
- (index = applied.keys.index(value)) &&
20
- (applied.values[index] == false)
18
+ applied[field] && applied[field].include?(value)
21
19
  else
22
- !applied.values.all?
20
+ applied[field] && !applied[field].empty?
23
21
  end
24
22
  end
25
23
 
26
- def applied_filters
27
- applied = {}
28
- _context[:fields].each do |field, options|
29
- if options && options[:applied] &&
30
- !(values = options[:applied].select { |_, v| v }.keys).empty?
31
- applied[field] = values
24
+ def applied_filters(included = nil)
25
+ applied = Hash.new { |hash, key| hash[key] = [] }
26
+ _scope.applied.flatten!.compact!.each do |result|
27
+ if included.nil? || result[:included] == included
28
+ applied[result[:field]] << result[:value]
32
29
  end
33
30
  end
34
31
  applied
35
32
  end
36
33
 
37
- private
38
-
39
- def field_options_for(field)
40
- _context[:fields][field.to_sym]
41
- end
42
-
43
34
  end
44
35
  end
45
36
  end
@@ -1,29 +1,32 @@
1
1
  module CloudSesame
2
- module Query
3
- module DSL
4
- module FieldAccessors
2
+ module Query
3
+ module DSL
4
+ module FieldAccessors
5
+ extend ClassSpecific
5
6
 
6
- def self.__define_accessor__(name)
7
- define_method(name) { |*values, &block| literal name, *values, &block }
8
- end
7
+ def self.__define_accessor__(name)
8
+ define_method name do |*values, &block|
9
+ literal name, *values, &block
10
+ end
11
+ end
9
12
 
10
- def literal(name, *values, &block)
11
- name = name.to_sym
13
+ def literal(name, *values, &block)
14
+ name = name.to_sym
15
+ values << __literal_block_handler__(name, block) if block_given?
16
+ _scope.children.field = name
17
+ _scope.children._return = _return
18
+ _scope.children.insert values
19
+ end
12
20
 
13
- if block_given?
14
- caller = block.binding.eval "self"
15
- options = _scope.context[:fields][name]
16
- domain = Domain::Literal.new(name, options, caller)
17
- node = domain._eval(&block)
18
- values << node
19
- end
21
+ private
20
22
 
21
- _scope.children.field = name
22
- _scope.children._return = _return
23
- _scope.children.insert values
24
- end
23
+ def __literal_block_handler__(name, block)
24
+ caller = block.binding.eval "self"
25
+ options = _scope.context[:fields][name]
26
+ Domain::Literal.new(name, options, caller)._eval(&block)
27
+ end
25
28
 
26
- end
27
- end
28
- end
29
+ end
30
+ end
31
+ end
29
32
  end
@@ -60,7 +60,7 @@ module CloudSesame
60
60
  end
61
61
 
62
62
  def build_literal(value)
63
- if value.kind_of?(AST::SingleExpressionOperator) || value.is_a?(AST::Literal)
63
+ if value.kind_of?(AST::Abstract::SingleExpressionOperator) || value.is_a?(AST::Literal)
64
64
  value.is_for field, _context[:fields][field]
65
65
  value
66
66
  else
@@ -0,0 +1,31 @@
1
+ module CloudSesame
2
+ module Query
3
+ module DSL
4
+ module InspectMethod
5
+
6
+ def inspect
7
+ string = green("#<#{ self.class }:#{ object_id }\n{")
8
+
9
+ string << compile.map { |k, v| "#{ green(k) } => #{ yellow(v) }" }.join(",\n ")
10
+ string << green('}')
11
+ string
12
+ end
13
+
14
+ private
15
+
16
+ def green(string)
17
+ color(32, string)
18
+ end
19
+
20
+ def yellow(string)
21
+ color(33, string)
22
+ end
23
+
24
+ def color(code, string)
25
+ "\e[#{ code }m#{ string }\e[0m"
26
+ end
27
+
28
+ end
29
+ end
30
+ end
31
+ end
@@ -4,15 +4,16 @@ module CloudSesame
4
4
  module SortMethods
5
5
 
6
6
  def sort(input = false)
7
- if input.is_a? Hash
8
- request.sort.sorting_attributes = input
7
+ if input.is_a?(Hash)
8
+ request.sort.attributes = input
9
9
  return self
10
10
  elsif input
11
- request.sort[input]
11
+ request.sort[input] = nil
12
+ return self
12
13
  elsif input.nil?
13
14
  return self
14
15
  else
15
- request.sort.sorting_attributes
16
+ request.sort.attributes
16
17
  end
17
18
  end
18
19
 
@@ -5,9 +5,8 @@ module CloudSesame
5
5
  attr_reader :context
6
6
 
7
7
  def initialize(context)
8
- @context = context
8
+ @context = context || {}
9
9
  end
10
-
11
10
  end
12
11
  end
13
12
  end
@@ -3,12 +3,8 @@ module CloudSesame
3
3
  module Node
4
4
  class Facet < Abstract
5
5
 
6
- def facet
7
- @facet ||= context
8
- end
9
-
10
6
  def compile
11
- { facet: JSON.dump(facet) } unless facet.empty?
7
+ JSON.dump(context) if context && !context.empty?
12
8
  end
13
9
 
14
10
  end
@@ -3,12 +3,25 @@ module CloudSesame
3
3
  module Node
4
4
  class FilterQuery < Abstract
5
5
 
6
+ EXCESS_WHITESPACES = Regexp.new(/\s{2,}/).freeze
7
+ ENDING_WHITESPACES = Regexp.new(/\s+\)$/).freeze
8
+
6
9
  def compile
7
- { filter_query: root.compile }
10
+ if (compiled = root.compile) && !(compiled = strip(compiled)).empty?
11
+ compiled
12
+ end
8
13
  end
9
14
 
10
15
  def root
11
- @root ||= CloudSesame::Query::AST::Root.new context
16
+ @root ||= AST::Root.new context
17
+ end
18
+
19
+ private
20
+
21
+ def strip(string)
22
+ string.gsub!(EXCESS_WHITESPACES, ' '.freeze)
23
+ string.gsub!(ENDING_WHITESPACES, ')'.freeze)
24
+ string
12
25
  end
13
26
 
14
27
  end
@@ -3,7 +3,7 @@ module CloudSesame
3
3
  module Node
4
4
  class Fuzziness
5
5
 
6
- EXCLUDING_TERMS = /^\-/
6
+ EXCLUDING_TERMS = /^\-/.freeze
7
7
 
8
8
  def initialize(&block)
9
9
 
@@ -28,13 +28,14 @@ module CloudSesame
28
28
  end
29
29
 
30
30
  def compile(string)
31
- "(#{ each_word_in(string) { |word| fuzziness(word) }.compact.join('+') })"
31
+ (compiled = each_word_in(string) { |word| fuzziness(word) }).compact!
32
+ "(#{ compiled.join('+') })"
32
33
  end
33
34
 
34
35
  private
35
36
 
36
37
  def each_word_in(string, &block)
37
- string.split(' ').map(&block)
38
+ string.split(' ').map!(&block)
38
39
  end
39
40
 
40
41
  def fuzziness(word)
@@ -6,11 +6,11 @@ module CloudSesame
6
6
  attr_writer :page, :size, :start
7
7
 
8
8
  def page
9
- @page ||= context[:page] || 1
9
+ @page ||= 1
10
10
  end
11
11
 
12
12
  def size
13
- @size ||= context[:size] || 10
13
+ @size ||= (context && context[:size]) || 10
14
14
  end
15
15
 
16
16
  def start
@@ -2,37 +2,24 @@ module CloudSesame
2
2
  module Query
3
3
  module Node
4
4
  class Query < Abstract
5
+ extend ClassSpecific
5
6
 
6
- attr_writer :query
7
-
8
- def query
9
- @query ||= context[:query]
10
- end
7
+ attr_accessor :query
11
8
 
12
9
  def compile
13
10
  if query && !query.empty?
14
11
  compiled = "(#{ query })"
15
12
 
16
- [fuzziness, sloppiness].each do |parser|
13
+ [context[:fuzziness], context[:sloppiness]].each do |parser|
17
14
  if parser && (parsed = parser.compile(query))
18
15
  compiled << "|" << parsed
19
16
  end
20
17
  end
21
18
 
22
- { query: compiled }
19
+ compiled
23
20
  end
24
21
  end
25
22
 
26
- private
27
-
28
- def fuzziness
29
- context[:fuzziness]
30
- end
31
-
32
- def sloppiness
33
- context[:sloppiness]
34
- end
35
-
36
23
  end
37
24
  end
38
25
  end
@@ -4,31 +4,21 @@ module CloudSesame
4
4
  class QueryOptions < Abstract
5
5
 
6
6
  def fields
7
- @fields ||= default_fields
7
+ @fields ||= build(context[:fields])
8
8
  end
9
9
 
10
10
  def compile
11
- {
12
- query_options: JSON.dump({
13
- fields: compile_fields
14
- })
15
- } unless fields.empty?
11
+ JSON.dump({ fields: fields.map(&:compile) }) unless fields.empty?
16
12
  end
17
13
 
18
14
  private
19
15
 
20
- def compile_fields
21
- fields.map(&:compile)
16
+ def build(fields)
17
+ fields ? fields.map { |field, opt| build_field(field, opt) } : []
22
18
  end
23
19
 
24
- def default_fields
25
- if context[:fields]
26
- context[:fields].map do |field, options|
27
- QueryOptionsField.new field, options[:weight]
28
- end
29
- else
30
- []
31
- end
20
+ def build_field(field, options)
21
+ QueryOptionsField.new field, options[:weight]
32
22
  end
33
23
 
34
24
  end
@@ -11,7 +11,9 @@ module CloudSesame
11
11
  end
12
12
 
13
13
  def compile
14
- "#{ field }#{ '^' + weight.to_s if weight }"
14
+ compiled = field.to_s
15
+ compiled << '^' << weight.to_s if weight
16
+ compiled
15
17
  end
16
18
 
17
19
  end
@@ -3,22 +3,20 @@ module CloudSesame
3
3
  module Node
4
4
  class QueryParser < Abstract
5
5
 
6
- TYPES = %w(simple structured lucene dismax)
7
-
8
- attr_writer :type
6
+ def type
7
+ @type ||= "simple"
8
+ end
9
9
 
10
- TYPES.each do |type|
11
- define_method type do
12
- self.type = type; self
13
- end
10
+ def simple
11
+ @type = "simple"
14
12
  end
15
13
 
16
- def type
17
- @type ||= (context[:query_parser] || :simple).to_s
14
+ def structured
15
+ @type = "structured"
18
16
  end
19
17
 
20
18
  def compile
21
- { query_parser: type.to_s }
19
+ type.to_s
22
20
  end
23
21
 
24
22
  end