CloudSesame 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +4 -0
  3. data/.rspec +2 -0
  4. data/Gemfile +3 -0
  5. data/Gemfile.lock +76 -0
  6. data/Guardfile +70 -0
  7. data/cloud_sesame.gemspec +25 -0
  8. data/lib/abstract_object.rb +67 -0
  9. data/lib/cloud_sesame.rb +77 -0
  10. data/lib/cloud_sesame/config/credential.rb +8 -0
  11. data/lib/cloud_sesame/domain/base.rb +70 -0
  12. data/lib/cloud_sesame/domain/client.rb +28 -0
  13. data/lib/cloud_sesame/domain/config.rb +8 -0
  14. data/lib/cloud_sesame/domain/context.rb +35 -0
  15. data/lib/cloud_sesame/query/ast/and.rb +9 -0
  16. data/lib/cloud_sesame/query/ast/compound_array.rb +73 -0
  17. data/lib/cloud_sesame/query/ast/leaf.rb +8 -0
  18. data/lib/cloud_sesame/query/ast/literal.rb +27 -0
  19. data/lib/cloud_sesame/query/ast/multi_branch.rb +27 -0
  20. data/lib/cloud_sesame/query/ast/not.rb +13 -0
  21. data/lib/cloud_sesame/query/ast/operator.rb +24 -0
  22. data/lib/cloud_sesame/query/ast/or.rb +9 -0
  23. data/lib/cloud_sesame/query/ast/prefix_literal.rb +17 -0
  24. data/lib/cloud_sesame/query/ast/root.rb +24 -0
  25. data/lib/cloud_sesame/query/ast/single_branch.rb +24 -0
  26. data/lib/cloud_sesame/query/ast/value.rb +38 -0
  27. data/lib/cloud_sesame/query/builder.rb +78 -0
  28. data/lib/cloud_sesame/query/dsl.rb +62 -0
  29. data/lib/cloud_sesame/query/dsl/and.rb +19 -0
  30. data/lib/cloud_sesame/query/dsl/base.rb +23 -0
  31. data/lib/cloud_sesame/query/dsl/filter_query.rb +47 -0
  32. data/lib/cloud_sesame/query/dsl/literal.rb +41 -0
  33. data/lib/cloud_sesame/query/dsl/or.rb +19 -0
  34. data/lib/cloud_sesame/query/dsl/range.rb +41 -0
  35. data/lib/cloud_sesame/query/dsl/scope.rb +24 -0
  36. data/lib/cloud_sesame/query/error/missing_operator_symbol.rb +8 -0
  37. data/lib/cloud_sesame/query/error/missing_query.rb +8 -0
  38. data/lib/cloud_sesame/query/node/abstract.rb +14 -0
  39. data/lib/cloud_sesame/query/node/facet.rb +14 -0
  40. data/lib/cloud_sesame/query/node/filter_query.rb +17 -0
  41. data/lib/cloud_sesame/query/node/page.rb +27 -0
  42. data/lib/cloud_sesame/query/node/query.rb +29 -0
  43. data/lib/cloud_sesame/query/node/query_options.rb +37 -0
  44. data/lib/cloud_sesame/query/node/query_options_field.rb +20 -0
  45. data/lib/cloud_sesame/query/node/query_parser.rb +27 -0
  46. data/lib/cloud_sesame/query/node/request.rb +71 -0
  47. data/lib/cloud_sesame/query/node/sort.rb +37 -0
  48. data/spec/abstract_object_spec.rb +103 -0
  49. data/spec/cloud_sesame/domain/base_spec.rb +27 -0
  50. data/spec/cloud_sesame/domain/context_spec.rb +24 -0
  51. data/spec/cloud_sesame/query/ast/and_spec.rb +13 -0
  52. data/spec/cloud_sesame/query/ast/literal_spec.rb +37 -0
  53. data/spec/cloud_sesame/query/ast/multi_branch_spec.rb +65 -0
  54. data/spec/cloud_sesame/query/ast/operator_spec.rb +30 -0
  55. data/spec/cloud_sesame/query/ast/or_spec.rb +13 -0
  56. data/spec/cloud_sesame/query/ast/root_spec.rb +43 -0
  57. data/spec/cloud_sesame/query/ast/value_spec.rb +40 -0
  58. data/spec/cloud_sesame/query/builder_spec.rb +12 -0
  59. data/spec/cloud_sesame/query/dsl/base_spec.rb +31 -0
  60. data/spec/cloud_sesame/query/dsl/filter_query_spec.rb +158 -0
  61. data/spec/cloud_sesame/query/dsl_spec.rb +96 -0
  62. data/spec/cloud_sesame/query/node/abstract_spec.rb +19 -0
  63. data/spec/cloud_sesame/query/node/facet_spec.rb +42 -0
  64. data/spec/cloud_sesame/query/node/filter_query_spec.rb +29 -0
  65. data/spec/cloud_sesame/query/node/page_spec.rb +58 -0
  66. data/spec/cloud_sesame/query/node/query_options_field_spec.rb +27 -0
  67. data/spec/cloud_sesame/query/node/query_options_spec.rb +56 -0
  68. data/spec/cloud_sesame/query/node/query_parser_spec.rb +37 -0
  69. data/spec/cloud_sesame/query/node/query_spec.rb +46 -0
  70. data/spec/cloud_sesame/query/node/request_spec.rb +71 -0
  71. data/spec/cloud_sesame/query/node/sort_spec.rb +76 -0
  72. data/spec/cloud_sesame_spec.rb +58 -0
  73. data/spec/spec_helper.rb +12 -0
  74. metadata +218 -0
@@ -0,0 +1,40 @@
1
+ require "spec_helper"
2
+
3
+ module CloudSesame
4
+ module Query
5
+ module AST
6
+ describe Value do
7
+
8
+ let(:value) { Value.new("Shoes") }
9
+
10
+ describe '#initialize' do
11
+ it 'should store the value' do
12
+ expect(value.data).to eq("Shoes")
13
+ end
14
+ end
15
+
16
+ describe '#compile' do
17
+ shared_examples 'return raw data' do
18
+ it 'should just return the data' do
19
+ expect(value.compile).to eq value.data
20
+ end
21
+ end
22
+ context 'when data is a string' do
23
+ it 'should escape the string' do
24
+ expect(value.compile).to eq "'#{value.data}'"
25
+ end
26
+ end
27
+ context 'when data is a range' do
28
+ let(:value) { Value.new('[100,}') }
29
+ include_examples 'return raw data'
30
+ end
31
+ context 'when data is a digit' do
32
+ let(:value) { Value.new(100) }
33
+ include_examples 'return raw data'
34
+ end
35
+ end
36
+
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+
3
+ module CloudSesame
4
+ module Query
5
+ describe Builder do
6
+ let(:client) { {} }
7
+ let(:searchable_class) { "Test" }
8
+ subject { Builder.new(client, searchable_class) }
9
+
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,31 @@
1
+ module CloudSesame
2
+ module Query
3
+ module DSL
4
+ describe Base do
5
+
6
+ class TestClass
7
+ include Base
8
+ end
9
+
10
+ subject { TestClass.new }
11
+
12
+ shared_examples 'return self instance' do
13
+ it 'should return itself' do
14
+ expect(result).to eq subject
15
+ end
16
+ end
17
+
18
+ describe '#method_return' do
19
+ let(:result) { subject.send(:method_return) }
20
+ include_examples 'return self instance'
21
+ end
22
+
23
+ describe '#method_scope' do
24
+ let(:result) { subject.send(:method_scope) }
25
+ include_examples 'return self instance'
26
+ end
27
+
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,158 @@
1
+ module CloudSesame
2
+ module Query
3
+ module DSL
4
+ describe FilterQuery do
5
+
6
+ class TestClass
7
+ include Base
8
+ include FilterQuery
9
+ def initialize
10
+ end
11
+ def children
12
+ @children ||= AST::CompoundArray.new.set_scope(self)
13
+ end
14
+ def context
15
+ @context ||= {}
16
+ end
17
+ end
18
+
19
+ subject { TestClass.new }
20
+
21
+ describe '#and' do
22
+ it 'should create an AND node' do
23
+ expect(AST::And).to receive(:new).with({})
24
+ subject.and
25
+ end
26
+ it 'should add the AND node to it\s children' do
27
+ expect(AST::And).to receive(:new).with({})
28
+ expect{ subject.and }.to change{ subject.children.size }.by(1)
29
+ end
30
+ it 'should return it\'s own scope' do
31
+ expect(subject.and).to eq subject
32
+ end
33
+ end
34
+
35
+ describe '#or' do
36
+ it 'should create an OR node' do
37
+ expect(AST::Or).to receive(:new).with({})
38
+ subject.or
39
+ end
40
+ it 'should add the OR node to it\s children' do
41
+ expect(AST::Or).to receive(:new).with({})
42
+ expect{ subject.or }.to change{ subject.children.size }.by(1)
43
+ end
44
+ it 'should return it\'s own scope' do
45
+ expect(subject.and).to eq subject
46
+ end
47
+ end
48
+
49
+ describe 'literal' do
50
+
51
+ it 'should create a literal node' do
52
+ expect(AST::Literal).to receive(:new).with('description', '123', Hash)
53
+ subject.literal('description', '123')
54
+ end
55
+ it 'should add the literal node to it\'s children' do
56
+ expect{ subject.literal('description', '123') }.to change{ subject.children.size }.by(1)
57
+ end
58
+ it 'should return the literal node' do
59
+ expect(subject.literal('description', '123')).to be_kind_of(AST::Literal)
60
+ end
61
+
62
+ context 'when field is define in context' do
63
+ before { subject.context[:fields] = { description: {} } }
64
+ # it 'should be triggered by calling the field name as a method' do
65
+ # expect(subject).to receive(:literal).with(:description, '123', {})
66
+ # subject.description "123"
67
+ # end
68
+ # it 'should accept multiple values' do
69
+ # expect(subject).to receive(:literal).exactly(3).times
70
+ # subject.description "123", "456", "789"
71
+ # end
72
+
73
+ it 'should return literal nodes in an array' do
74
+ result = subject.description("123", "456", "789")
75
+ expect(result).to include(AST::Literal)
76
+ end
77
+ end
78
+
79
+ context 'when field is not defined' do
80
+ it 'should raise method missing error when calling the field name as a method' do
81
+ expect{ subject.not_defined() }.to raise_error(NoMethodError)
82
+ end
83
+ end
84
+ end
85
+
86
+ # describe 'prefix' do
87
+ # it 'should set the literal prefix option to true' do
88
+ # literals = (1..3).map { |i| AST::Literal.new(:int, i) }
89
+ # subject.prefix(literals)
90
+
91
+ # literals.each do |literal|
92
+ # expect(literal.options).to include(prefix: true)
93
+ # end
94
+
95
+ # end
96
+ # end
97
+
98
+ describe 'included?' do
99
+ before { subject.context[:fields] = { tags: {}, description: {} } }
100
+ context 'when there is a field and no value' do
101
+ it 'should return true if the request contains the field in the filter query' do
102
+ subject.and{tags('women')}
103
+ expect(subject.included?(:tags)).to be_truthy
104
+ end
105
+
106
+ it 'should return false if the request does not contain the field in the filter query' do
107
+ subject.and{tags.not('women')}
108
+ expect(subject.included?(:tags)).to be_falsey
109
+ end
110
+
111
+ end
112
+ context 'when there is a field and a value' do
113
+ it 'should return true if the request contains the field and the value in the filter query' do
114
+ subject.and{tags('women')}
115
+ expect(subject.included?(:tags, 'women')).to be_truthy
116
+ end
117
+
118
+ it 'should return false if the request does not contain the field or the value in the filter query' do
119
+ subject.and{tags('women')}
120
+ expect(subject.included?(:tags, 'men')).to be_falsey
121
+ expect(subject.included?(:description, 'women')).to be_falsey
122
+ end
123
+ end
124
+ end
125
+
126
+
127
+ describe 'excluded?' do
128
+ before { subject.context[:fields] = { tags: {}, description: {} } }
129
+ context 'when there is a field and no value' do
130
+ it 'should return true if the request excludes the field in the filter query' do
131
+ subject.and{tags('women')}
132
+ expect(subject.excluded?(:tags)).to be_falsey
133
+ end
134
+
135
+ it 'should return false if the request does not exclude the field in the filter query' do
136
+ subject.and{tags.not('women')}
137
+ expect(subject.excluded?(:tags)).to be_truthy
138
+ end
139
+ end
140
+
141
+ context 'when there is a field and a value' do
142
+ it 'should return true if the request excludes the field and the value in the filter query' do
143
+ subject.and{tags.not('women')}
144
+ expect(subject.excluded?(:tags, 'women')).to be_truthy
145
+ end
146
+
147
+ it 'should return false if the request does not exclude the field or the value in the filter query' do
148
+ subject.and{tags('women')}
149
+ expect(subject.excluded?(:tags, 'men')).to be_falsey
150
+ expect(subject.excluded?(:tags, 'women')).to be_falsey
151
+ end
152
+ end
153
+ end
154
+
155
+ end
156
+ end
157
+ end
158
+ end
@@ -0,0 +1,96 @@
1
+ # module CloudSesame
2
+ # module Query
3
+ # describe DSL do
4
+
5
+ # class TestClass
6
+ # include DSL
7
+ # def context
8
+ # @context ||= {}
9
+ # end
10
+ # def children
11
+ # @children ||= []
12
+ # end
13
+ # end
14
+
15
+ # subject { TestClass.new }
16
+
17
+ # describe '#and' do
18
+ # it 'should create an AND node' do
19
+ # expect(AST::And).to receive(:new).with({})
20
+ # subject.and
21
+ # end
22
+ # it 'should add the AND node to it\s children' do
23
+ # expect(AST::And).to receive(:new).with({})
24
+ # expect{ subject.and }.to change{ subject.children.size }.by(1)
25
+ # end
26
+ # it 'should return it\'s own scope' do
27
+ # expect(subject.and).to eq subject
28
+ # end
29
+ # end
30
+
31
+ # describe '#or' do
32
+ # it 'should create an OR node' do
33
+ # expect(AST::Or).to receive(:new).with({})
34
+ # subject.or
35
+ # end
36
+ # it 'should add the OR node to it\s children' do
37
+ # expect(AST::Or).to receive(:new).with({})
38
+ # expect{ subject.or }.to change{ subject.children.size }.by(1)
39
+ # end
40
+ # it 'should return it\'s own scope' do
41
+ # expect(subject.and).to eq subject
42
+ # end
43
+ # end
44
+
45
+ # describe 'literal' do
46
+
47
+ # it 'should create a literal node' do
48
+ # expect(AST::Literal).to receive(:new).with('description', '123', Hash)
49
+ # subject.literal('description', '123')
50
+ # end
51
+ # it 'should add the literal node to it\'s children' do
52
+ # expect{ subject.literal('description', '123') }.to change{ subject.children.size }.by(1)
53
+ # end
54
+ # it 'should return the literal node' do
55
+ # expect(subject.literal('description', '123')).to be_kind_of(AST::Literal)
56
+ # end
57
+
58
+ # context 'when field is define in context' do
59
+ # before { subject.context[:fields] = { description: {} } }
60
+ # it 'should be triggered by calling the field name as a method' do
61
+ # expect(subject).to receive(:literal).with(:description, '123', {})
62
+ # subject.description "123"
63
+ # end
64
+ # it 'should accept multiple values' do
65
+ # expect(subject).to receive(:literal).exactly(3).times
66
+ # subject.description "123", "456", "789"
67
+ # end
68
+
69
+ # it 'should return literal nodes in an array' do
70
+ # result = subject.description("123", "456", "789")
71
+ # expect(result).to include(AST::Literal)
72
+ # end
73
+ # end
74
+
75
+ # context 'when field is not defined' do
76
+ # it 'should raise method missing error when calling the field name as a method' do
77
+ # expect{ subject.not_defined() }.to raise_error(NoMethodError)
78
+ # end
79
+ # end
80
+ # end
81
+
82
+ # describe 'prefix' do
83
+ # it 'should set the literal prefix option to true' do
84
+ # literals = (1..3).map { |i| AST::Literal.new(:int, i) }
85
+ # subject.prefix(literals)
86
+
87
+ # literals.each do |literal|
88
+ # expect(literal.options).to include(prefix: true)
89
+ # end
90
+
91
+ # end
92
+ # end
93
+
94
+ # end
95
+ # end
96
+ # end
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ module CloudSesame
4
+ module Query
5
+ module Node
6
+ describe Abstract do
7
+ let(:context) { :context }
8
+ subject { Abstract.new(context) }
9
+
10
+ describe '#initialize' do
11
+ it 'should store context' do
12
+ expect(subject.context).to eq context
13
+ end
14
+ end
15
+
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+
3
+ module CloudSesame
4
+ module Query
5
+ module Node
6
+ describe Facet do
7
+ let(:facet) { Facet.new(context) }
8
+ let(:context) { Domain::Context.new(facet_options) }
9
+ describe '#facet' do
10
+ context 'when default facet is defined' do
11
+ let(:facet_options) { { price: { size: 100 } } }
12
+ it 'should return the default facet options' do
13
+ expect(facet.facet).to include(facet_options)
14
+ end
15
+ end
16
+ context 'when default facet is not defined' do
17
+ let(:facet_options) { {} }
18
+ it 'should return an empty facet options' do
19
+ expect(facet.facet).to include(facet_options)
20
+ end
21
+ end
22
+ end
23
+
24
+ describe '#compile' do
25
+ context 'when facet is not empty' do
26
+ let(:facet_options) { { price: { size: 100 } } }
27
+ it 'should return stringified JSON facet' do
28
+ expect(facet.compile).to include facet: JSON.dump(facet_options)
29
+ end
30
+ end
31
+ context 'when facet is empty' do
32
+ let(:facet_options) { { } }
33
+ it 'should return nil' do
34
+ expect(facet.compile).to eq nil
35
+ end
36
+ end
37
+ end
38
+
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ module CloudSesame
4
+ module Query
5
+ module Node
6
+ describe FilterQuery do
7
+ subject { FilterQuery.new({}) }
8
+
9
+ describe '#compile' do
10
+ it 'should compile root' do
11
+ expect(subject.root).to receive(:compile)
12
+ subject.compile
13
+ end
14
+ it 'should return an hash with filter query' do
15
+ expect(subject.compile).to include(filter_query: subject.root.compile )
16
+ end
17
+ end
18
+
19
+ describe '#root' do
20
+ it 'should instantiate and return an instance of Root' do
21
+ expect(AST::Root).to receive(:new).with(subject.context).and_call_original
22
+ expect(subject.root).to be_kind_of(AST::Root)
23
+ end
24
+ end
25
+
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,58 @@
1
+ require "spec_helper"
2
+
3
+ module CloudSesame
4
+ module Query
5
+ module Node
6
+ describe Page do
7
+ let(:node) { Page.new(arguments) }
8
+
9
+ describe '#initialize' do
10
+ context 'when arguments passed in' do
11
+ let(:arguments) { { page: 2, size: 13 } }
12
+ it 'should initialize the page with the page argument' do
13
+ expect(node.page).to eq 2
14
+ end
15
+ it 'should initialize the size with the size argument' do
16
+ expect(node.size).to eq 13
17
+ end
18
+ end
19
+ context 'when arguments NOT passed in' do
20
+ let(:arguments) { {} }
21
+ it 'should default the page to 1' do
22
+ expect(node.page).to eq 1
23
+ end
24
+ it 'should default the size to 10' do
25
+ expect(node.size).to eq 10
26
+ end
27
+ end
28
+ end
29
+
30
+ describe 'start' do
31
+ [{
32
+ page: 1, size: 100, expect_start: 0
33
+ }, {
34
+ page: 2, size: 10, expect_start: 10
35
+ }, {
36
+ page: 3, size: 13, expect_start: 26
37
+ }].each do |arguments|
38
+ it 'should calculate and return the starting point' do
39
+ node = Page.new arguments
40
+ expect(node.start).to eq arguments[:expect_start]
41
+ end
42
+ end
43
+ end
44
+
45
+ describe '#run' do
46
+ let(:arguments) { { page: 3, size: 13 } }
47
+ it 'should return the calculated start' do
48
+ expect(node.compile).to include start: node.start
49
+ end
50
+ it 'should return the size' do
51
+ expect(node.compile).to include size: arguments[:size]
52
+ end
53
+ end
54
+
55
+ end
56
+ end
57
+ end
58
+ end