CloudSesame 0.1.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 (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