CloudSesame 0.3.6 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/cloud_sesame.gemspec +1 -1
- data/lib/cloud_sesame/query/ast/literal.rb +7 -15
- data/lib/cloud_sesame/query/ast/near.rb +2 -2
- data/lib/cloud_sesame/query/ast/not.rb +2 -2
- data/lib/cloud_sesame/query/ast/operator.rb +0 -1
- data/lib/cloud_sesame/query/ast/range_value.rb +20 -12
- data/lib/cloud_sesame/query/ast/single_expression_operator.rb +3 -3
- data/lib/cloud_sesame/query/ast/value.rb +3 -4
- data/lib/cloud_sesame/query/builder.rb +1 -1
- data/lib/cloud_sesame/query/dsl/base.rb +4 -0
- data/lib/cloud_sesame/query/dsl/block_methods.rb +17 -3
- data/lib/cloud_sesame/query/dsl/filter_query_methods.rb +29 -14
- data/spec/cloud_sesame/query/ast/operator_spec.rb +0 -9
- data/spec/cloud_sesame_spec.rb +38 -21
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a97ed18065996a1ded5cc2b8719d43e668383f4f
|
4
|
+
data.tar.gz: 94b4b851f28cbe7b50cd7f3b7d0ce45373e07e87
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2f62458643e0f3e95e404b326317016c07b94657a7f17ce471601d9f603667077affd7cf4319d7dd34553818f1e85f9a6e099973f701e5cc2c4e599e0893c08d
|
7
|
+
data.tar.gz: 756f7b2e14460b142b8ed59d5ac63dbd3f66deff02f4af71f57b4e9213e5b8ac3c5655e42796d2a20a399c0e9eedf26c88fe00d4bf295e6ddc4a1978eb242652
|
data/Gemfile.lock
CHANGED
data/cloud_sesame.gemspec
CHANGED
@@ -11,12 +11,10 @@ module CloudSesame
|
|
11
11
|
|
12
12
|
def initialize(field = nil, value = nil, options = {}, &block)
|
13
13
|
@field = field
|
14
|
-
|
15
14
|
@value = Value.parse value if value
|
16
15
|
@value = Value.parse ValueEvaluator.new.instance_exec &block if block_given?
|
17
|
-
|
18
16
|
@options = options || {}
|
19
|
-
|
17
|
+
applied[@value] = true
|
20
18
|
end
|
21
19
|
|
22
20
|
def is_for(field, options)
|
@@ -25,27 +23,21 @@ module CloudSesame
|
|
25
23
|
end
|
26
24
|
|
27
25
|
def is_excluded
|
28
|
-
|
29
|
-
(options[:excluded] ||= []) << value
|
26
|
+
applied[value] = applied[value] == false ? true : false
|
30
27
|
end
|
31
28
|
|
32
29
|
def as_field
|
33
|
-
|
30
|
+
options[:as] || field
|
34
31
|
end
|
35
32
|
|
36
33
|
def compile(detailed = false)
|
37
|
-
|
34
|
+
detailed ? detailed_format : standard_format
|
38
35
|
end
|
39
36
|
|
40
37
|
private
|
41
38
|
|
42
|
-
def
|
43
|
-
|
44
|
-
end
|
45
|
-
|
46
|
-
def recompile(detailed)
|
47
|
-
@compiled_value = value
|
48
|
-
@compiled = detailed ? detailed_format : standard_format
|
39
|
+
def applied
|
40
|
+
options[:applied] ||= {}
|
49
41
|
end
|
50
42
|
|
51
43
|
def standard_format
|
@@ -53,7 +45,7 @@ module CloudSesame
|
|
53
45
|
end
|
54
46
|
|
55
47
|
def detailed_format
|
56
|
-
"field=#{ escape as_field } #{ value.compile }"
|
48
|
+
"field=#{ escape as_field.to_s } #{ value.compile }"
|
57
49
|
end
|
58
50
|
|
59
51
|
def escape(data)
|
@@ -5,8 +5,8 @@ module CloudSesame
|
|
5
5
|
DETAILED = true
|
6
6
|
SYMBOL = :near
|
7
7
|
|
8
|
-
def compile
|
9
|
-
"(#{ symbol }#{ boost }#{ distance } #{ child.compile
|
8
|
+
def compile(detailed = nil)
|
9
|
+
"(#{ symbol }#{ boost }#{ distance } #{ child.compile operator_detailed })" if child
|
10
10
|
end
|
11
11
|
|
12
12
|
def distance
|
@@ -3,22 +3,18 @@ module CloudSesame
|
|
3
3
|
module AST
|
4
4
|
class RangeValue < Value
|
5
5
|
|
6
|
-
|
6
|
+
RANGE_FORMAT = /\A(\[|{)(.*),(.*)(\}|\])\z/
|
7
7
|
|
8
8
|
def initialize(value = nil)
|
9
9
|
@data = if value.kind_of?(Range)
|
10
10
|
range_to_array(value)
|
11
|
-
elsif value.is_a?(String) && (match =
|
11
|
+
elsif value.is_a?(String) && (match = string_format?(value))
|
12
12
|
@data = match.captures
|
13
13
|
else
|
14
14
|
default_range
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
-
def compile
|
19
|
-
"#{ lb }#{ l.to_s },#{ u.to_s }#{ ub }"
|
20
|
-
end
|
21
|
-
|
22
18
|
def gt(value = nil)
|
23
19
|
data[0], data[1] = '{', Value.parse(value) if value
|
24
20
|
return self
|
@@ -39,18 +35,22 @@ module CloudSesame
|
|
39
35
|
return self
|
40
36
|
end
|
41
37
|
|
42
|
-
def
|
43
|
-
|
38
|
+
def compile
|
39
|
+
"#{ lb }#{ l.to_s },#{ u.to_s }#{ ub }"
|
44
40
|
end
|
45
41
|
|
46
|
-
def
|
47
|
-
data
|
42
|
+
def ==(object)
|
43
|
+
data == Value.parse(object).data
|
48
44
|
end
|
49
45
|
|
50
46
|
private
|
51
47
|
|
52
|
-
def
|
53
|
-
|
48
|
+
def string_format?(string)
|
49
|
+
RANGE_FORMAT.match string.tr(' ', '')
|
50
|
+
end
|
51
|
+
|
52
|
+
def range_to_array(range)
|
53
|
+
['[', range.begin, range.end, end_symbol(range)]
|
54
54
|
end
|
55
55
|
|
56
56
|
def end_symbol(value)
|
@@ -61,6 +61,14 @@ module CloudSesame
|
|
61
61
|
['{', nil, nil, '}']
|
62
62
|
end
|
63
63
|
|
64
|
+
def l
|
65
|
+
data[1]
|
66
|
+
end
|
67
|
+
|
68
|
+
def u
|
69
|
+
data[2]
|
70
|
+
end
|
71
|
+
|
64
72
|
def lb
|
65
73
|
data[1] ? data[0] : '{'
|
66
74
|
end
|
@@ -21,11 +21,11 @@ module CloudSesame
|
|
21
21
|
self.child = object
|
22
22
|
end
|
23
23
|
|
24
|
-
def compile
|
25
|
-
"(#{ symbol }#{ boost } #{ child.compile
|
24
|
+
def compile(detailed = nil)
|
25
|
+
"(#{ symbol }#{ boost } #{ child.compile operator_detailed })" if child
|
26
26
|
end
|
27
27
|
|
28
|
-
def
|
28
|
+
def operator_detailed
|
29
29
|
self.class::DETAILED
|
30
30
|
end
|
31
31
|
|
@@ -3,7 +3,7 @@ module CloudSesame
|
|
3
3
|
module AST
|
4
4
|
class Value
|
5
5
|
|
6
|
-
RANGE_FORMAT = /\A
|
6
|
+
RANGE_FORMAT = /\A(\[|{)(.*),(.*)(\}|\])\z/
|
7
7
|
DIGIT_FORMAT = /\A\d+(.\d+)?\z/
|
8
8
|
SINGLE_QUATE = /\'/
|
9
9
|
ESCAPE_QUATE = "\\'"
|
@@ -12,15 +12,14 @@ module CloudSesame
|
|
12
12
|
|
13
13
|
def self.parse(value)
|
14
14
|
return value if value.kind_of? AST::Value
|
15
|
+
return AST::NumericValue.new(value) if value.is_a?(Numeric) || (value.is_a?(String) && DIGIT_FORMAT =~ value)
|
15
16
|
return AST::DateValue.new(value) if value.kind_of?(Date) || value.kind_of?(Time)
|
16
17
|
return AST::RangeValue.new(value) if value.kind_of?(Range) || (value.is_a?(String) && RANGE_FORMAT =~ value)
|
17
|
-
return AST::NumericValue.new(value) if value.is_a?(Numeric) || (value.is_a?(String) && DIGIT_FORMAT =~ value)
|
18
18
|
AST::Value.new(value)
|
19
19
|
end
|
20
20
|
|
21
21
|
def initialize(data)
|
22
22
|
@data = data
|
23
|
-
@compiled = compile
|
24
23
|
end
|
25
24
|
|
26
25
|
def compile
|
@@ -46,7 +45,7 @@ module CloudSesame
|
|
46
45
|
@compiled = escape @compiled_data
|
47
46
|
end
|
48
47
|
|
49
|
-
def escape(data
|
48
|
+
def escape(data)
|
50
49
|
"'#{ data.gsub(SINGLE_QUATE) { ESCAPE_QUATE } }'"
|
51
50
|
end
|
52
51
|
|
@@ -58,7 +58,7 @@ module CloudSesame
|
|
58
58
|
def search
|
59
59
|
compiled = request.compile
|
60
60
|
raise Error::MissingQuery.new("Query or FilterQuery can not be empty!") if !compiled[:query] || compiled[:query].empty?
|
61
|
-
@response = client.search compiled
|
61
|
+
@response = searchable.cloudsearch.client.search compiled
|
62
62
|
end
|
63
63
|
|
64
64
|
private
|
@@ -26,19 +26,33 @@ module CloudSesame
|
|
26
26
|
private
|
27
27
|
|
28
28
|
def block_style_dsl(klass, options, &block)
|
29
|
-
node = klass.new dsl_context, options
|
29
|
+
node = klass.new dsl_context, options
|
30
30
|
if block_given?
|
31
|
+
extract_caller_from block if on_root_level?
|
32
|
+
node.instance_eval &block
|
31
33
|
dsl_scope << node
|
32
34
|
dsl_return node
|
33
35
|
else
|
34
|
-
|
36
|
+
chaining_relation_for(node)
|
35
37
|
end
|
36
38
|
end
|
37
39
|
|
38
|
-
def
|
40
|
+
def chaining_relation_for(node)
|
39
41
|
AST::BlockChainingRelation.new(dsl_scope, dsl_return, node)
|
40
42
|
end
|
41
43
|
|
44
|
+
def on_root_level?
|
45
|
+
dsl_scope.is_a?(AST::Root)
|
46
|
+
end
|
47
|
+
|
48
|
+
def extract_caller_from(block)
|
49
|
+
dsl_context[:caller] = block.binding.eval "self"
|
50
|
+
end
|
51
|
+
|
52
|
+
def method_missing(name, *args, &block)
|
53
|
+
dsl_caller ? dsl_caller.send(name, *args, &block) : super
|
54
|
+
end
|
55
|
+
|
42
56
|
end
|
43
57
|
end
|
44
58
|
end
|
@@ -4,27 +4,42 @@ module CloudSesame
|
|
4
4
|
module FilterQueryMethods
|
5
5
|
|
6
6
|
def included?(field, value = nil)
|
7
|
-
(
|
8
|
-
(
|
9
|
-
(
|
7
|
+
!!(
|
8
|
+
(field_options = dsl_context[:fields][field]) &&
|
9
|
+
(applied = field_options[:applied]) &&
|
10
|
+
(
|
11
|
+
(!value && applied.values.any?) ||
|
12
|
+
(
|
13
|
+
value && (index = applied.keys.index(value)) &&
|
14
|
+
(field_options[:applied].values[index] != false)
|
15
|
+
)
|
16
|
+
)
|
10
17
|
)
|
11
18
|
end
|
12
19
|
|
13
20
|
def excluded?(field, value = nil)
|
14
|
-
(
|
15
|
-
(
|
16
|
-
(
|
21
|
+
!!(
|
22
|
+
(field_options = dsl_context[:fields][field]) &&
|
23
|
+
(applied = field_options[:applied]) &&
|
24
|
+
(
|
25
|
+
(!value && !applied.values.all?) ||
|
26
|
+
(
|
27
|
+
value && (index = applied.keys.index(value)) &&
|
28
|
+
field_options[:applied].values[index] == false
|
29
|
+
)
|
30
|
+
)
|
17
31
|
)
|
18
32
|
end
|
19
33
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
34
|
+
def applied_filters
|
35
|
+
applied = {}
|
36
|
+
dsl_context[:fields].each do |field, options|
|
37
|
+
if options && options[:applied] &&
|
38
|
+
!(values = options[:applied].select { |k, v| v }.keys).empty?
|
39
|
+
applied[field] = values
|
40
|
+
end
|
41
|
+
end
|
42
|
+
applied
|
28
43
|
end
|
29
44
|
|
30
45
|
end
|
@@ -9,15 +9,6 @@ module CloudSesame
|
|
9
9
|
let(:block) { Proc.new {} }
|
10
10
|
subject { Operator.new(context, options, &block) }
|
11
11
|
|
12
|
-
describe '#initialize' do
|
13
|
-
context 'given a block' do
|
14
|
-
let(:block) { Proc.new { context[:name] = :test } }
|
15
|
-
it 'should evalute the block' do
|
16
|
-
expect(subject.context[:name]).to eq :test
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
12
|
describe '#boost' do
|
22
13
|
context 'given boost option' do
|
23
14
|
let(:options) {{ boost: 2 }}
|
data/spec/cloud_sesame_spec.rb
CHANGED
@@ -62,22 +62,23 @@
|
|
62
62
|
# end
|
63
63
|
|
64
64
|
|
65
|
-
#
|
66
|
-
#
|
67
|
-
#
|
65
|
+
# n = 10_000
|
66
|
+
# q = nil
|
67
|
+
# result = RubyProf.profile do
|
68
|
+
# n.times do
|
68
69
|
# q = Product.cloudsearch.query("black jacket").sort(price: :asc).page(1).size(1000).and {
|
69
70
|
# or! {
|
70
|
-
# tags "
|
71
|
+
# tags "1", "2"
|
71
72
|
# and! {
|
72
|
-
# tags.not "
|
73
|
+
# tags.not "3", "4"
|
73
74
|
# }
|
74
75
|
# and!.not {
|
75
|
-
# tags.start_with "
|
76
|
-
# tags.not.start_with "
|
77
|
-
# tags.not.near "
|
78
|
-
# tags start_with("
|
79
|
-
# tags term "
|
80
|
-
# tags phrase "
|
76
|
+
# tags.start_with "5", "6"
|
77
|
+
# tags.not.start_with "7"
|
78
|
+
# tags.not.near "8"
|
79
|
+
# tags start_with("9"), near("10")
|
80
|
+
# tags term "11"
|
81
|
+
# tags phrase "12"
|
81
82
|
# }
|
82
83
|
# or!.not {
|
83
84
|
# price 25..100
|
@@ -91,15 +92,31 @@
|
|
91
92
|
# created_at gte(Date.today).lt(Date.today + 3)
|
92
93
|
# }
|
93
94
|
# }
|
94
|
-
# }
|
95
|
-
|
96
|
-
# # end
|
97
|
-
# # end
|
98
|
-
# # printer = RubyProf::FlatPrinter.new(result)
|
99
|
-
# # printer.print(STDOUT, {})
|
100
|
-
|
101
|
-
# # q = Product.cloudsearch.and {
|
102
|
-
# binding.pry
|
103
|
-
# # }
|
95
|
+
# }
|
96
|
+
# a = q.applied_filters
|
104
97
|
|
98
|
+
# end
|
99
|
+
# end
|
100
|
+
# printer = RubyProf::FlatPrinter.new(result)
|
101
|
+
# printer.print(STDOUT, {})
|
102
|
+
|
103
|
+
# binding.pry
|
104
|
+
|
105
|
+
# # class TestClass
|
106
|
+
# # def initialize
|
107
|
+
# # @name = "scott"
|
108
|
+
# # end
|
109
|
+
# # def greeting
|
110
|
+
# # "hello world!"
|
111
|
+
# # end
|
112
|
+
# # def test_method
|
113
|
+
# # local = :test
|
114
|
+
# # q = Product.cloudsearch.and {
|
115
|
+
# # binding.pry
|
116
|
+
# # }
|
117
|
+
# # end
|
118
|
+
# # end
|
119
|
+
|
120
|
+
# # test = TestClass.new
|
121
|
+
# # test.test_method
|
105
122
|
# end
|