CloudSesame 0.6.8 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
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